#include "roc/Gpio.h"
#include "roc/defines_gpio.h"
using roc::Board;
/*!
* \class roc::Gpio
* \brief Device class with all GPIO access methods
*
*/
//----------------------------------------------------------------------------
//! Constructor with full addressing path information.
/*!
* Sets up \c Gpio object with full addressing information
* \param board ROC board pointer
*/
roc::Gpio::Gpio(roc::Board* board) :
roc::Peripheral(board)
{
}
//----------------------------------------------------------------------------
roc::Gpio::~Gpio()
{
}
//----------------------------------------------------------------------------
//! Set baud rate for sync message sender or receiver
/*!
* \param gpio_nr The number of the GPIO port
* \li 1 for SYNC_M the sync message sender
* \li 2 for SYNC_S0 the sync message receiver channel 0
* \li 3 for SYNC_S1 the sync message receiver channel 1
* \param offset number of 250 MHz clock cycles between the start bit edge
* and the first data capture
* \param odd number of 250 MHz clock cycles between the (2n + 1) data capture
* and the (2n + 2) data capture
* \param even number of 250 MHz clock cycles between the (2n + 0) data capture
* and the (2n + 1) data capture
* \returns see \ref roc_board_opererr, or -1 of gpio_nr out of range
*
* \sa setSyncBaud(int gpio_nr, uint32_t ratediv)
* \sa getSyncBaud(int gpio_nr, uint32_t& offset,
* uint32_t& odd, uint32_t& even)
*/
int roc::Gpio::setSyncBaud(int gpio_nr, uint32_t offset,
uint32_t odd, uint32_t even)
{
uint32_t addr_offset[3] = {ROC_SYNC1_BAUD_START,
ROC_SYNC2_BAUD_START,
ROC_SYNC3_BAUD_START};
uint32_t addr_odd[3] = {ROC_SYNC1_BAUD1,
ROC_SYNC2_BAUD1,
ROC_SYNC3_BAUD1};
uint32_t addr_even[3] = {ROC_SYNC1_BAUD2,
ROC_SYNC2_BAUD2,
ROC_SYNC3_BAUD2};
if (gpio_nr < 1 || gpio_nr > 3) return -1;
int rc = board().operPPP(addr_offset[gpio_nr-1], offset-1,
addr_odd[gpio_nr-1], odd-1,
addr_even[gpio_nr-1], even-1);
return rc;
}
//----------------------------------------------------------------------------
//! Set baud rate for sync message sender or receiver
/*!
* \param gpio_nr The number of the GPIO port
* \li 1 for SYNC_M the sync message sender
* \li 2 for SYNC_S0 the sync message receiver channel 0
* \li 3 for SYNC_S1 the sync message receiver channel 1
* \param ratediv rate divider factor
* \returns see \ref roc_board_opererr, or
* \li -1 if \a gpio_nr out of range
* \li -2 if \a ratediv too large (>511)
*
* \sa getSyncBaud(int gpio_nr, uint32_t ratediv)
*/
int roc::Gpio::setSyncBaud(int gpio_nr, uint32_t ratediv)
{
uint32_t offset = ratediv/4;
uint32_t odd = ratediv/2;
uint32_t even = ratediv-odd;
if (odd > 255 || even > 255) return -2;
return setSyncBaud(gpio_nr, offset, odd, even);
}
//----------------------------------------------------------------------------
//! Get baud rate settings for sync message sender or receiver
/*!
* set setSyncBaud(int gpio_nr, uint32_t& offset, uint32_t& odd, uint32_t& even)
* for detailed description of the arguments.
*/
int roc::Gpio::getSyncBaud(int gpio_nr, uint32_t& offset,
uint32_t& odd, uint32_t& even)
{
uint32_t addr_offset[3] = {ROC_SYNC1_BAUD_START,
ROC_SYNC2_BAUD_START,
ROC_SYNC3_BAUD_START};
uint32_t addr_odd[3] = {ROC_SYNC1_BAUD1,
ROC_SYNC2_BAUD1,
ROC_SYNC3_BAUD1};
uint32_t addr_even[3] = {ROC_SYNC1_BAUD2,
ROC_SYNC2_BAUD2,
ROC_SYNC3_BAUD2};
if (gpio_nr < 1 || gpio_nr > 3) return -1;
uint32_t offset_raw;
uint32_t odd_raw;
uint32_t even_raw;
int rc = board().operGGG(addr_offset[gpio_nr-1], offset_raw,
addr_odd[gpio_nr-1], odd_raw,
addr_even[gpio_nr-1], even_raw);
offset = offset_raw + 1;
odd = odd_raw + 1;
even = even_raw + 1;
return rc;
}
//----------------------------------------------------------------------------
//! Get baud rate divider setting for sync message sender or receiver
/*!
* see setSyncBaud(int gpio_nr, uint32_t ratediv)
* for detailed description of the arguments.
*/
int roc::Gpio::getSyncBaud(int gpio_nr, uint32_t& ratediv)
{
uint32_t offset;
uint32_t odd;
uint32_t even;
int rc = getSyncBaud(gpio_nr, offset, odd, even);
ratediv = odd + even;
return rc;
}
//----------------------------------------------------------------------------
//! Sets the synch message sender scale down to 1 to 2** \a val.
/*!
* The sync message sender sends a sync message either at every epoch or
* scaled down every every 2nd, or every 4th, or every 2**n'th epoch.
* This methods sets the scale down exponent, allowed values for \a val
* are 0 to 21. Since the epoch is 16.384 usec this allows to adjust the
* sync message period between ~16 usec and 35 sec.
*
* \param val sync message scale down exponent, range 0 to 21.
* \returns see \ref roc_board_opererr
*
* \par Table of scale down factors and resulting periods:
*
* \a val | period | Comment |
* 0 | 16.384 usec | every epoch |
* 1 | 32.768 usec | every 2nd epoch |
* 2 | 65.536 usec | every 4th epoch |
* 3 | 131.072 usec | every 8th epoch |
* 4 | 262.144 usec | every 16th epoch |
* 5 | 524.288 usec | every 32th epoch |
* 6 | ~1.05 msec | every 64th epoch |
* 7 | ~2.09 msec | every 128th epoch |
* 8 | ~4.19 msec | every 256th epoch |
* 9 | ~8.38 msec | every 512th epoch |
* 10 | ~16.77 msec | every 1024th epoch |
* 11 | ~33.55 msec | every 2048th epoch |
* 12 | ~67.11 msec | every 4096th epoch |
* 13 | ~134.21 msec | every 8192th epoch |
* 14 | ~268.43 msec | every 16384th epoch |
* 15 | ~536.69 msec | every 32768th epoch |
* 16 | ~1.07 sec | every 65536th epoch |
* 17 | ~2.15 sec | every 131072th epoch |
* 18 | ~4.29 sec | every 262144th epoch |
* 19 | ~8.59 sec | every 524288th epoch |
* 20 | ~17.18 sec | every 1048576th epoch |
* 21 | ~34.35 sec | every 2097152th epoch |
*
*/
int roc::Gpio::setSyncScale(uint32_t val)
{
return board().put(ROC_SYNC1_SCALEDOWN, val);
}
//----------------------------------------------------------------------------
//! Get the synch message sender scale down.
/*!
* \param val sync message scale down exponent
* \returns see \ref roc_board_opererr
*/
int roc::Gpio::getSyncScale(uint32_t& val)
{
return board().get(ROC_SYNC1_SCALEDOWN, val);
}
//----------------------------------------------------------------------------
//! Read GPIO configuration register.
/*!
* \param mask read value of GPIO configuration register
* \returns see \ref roc_board_opererr
* \sa setConfig(), unpackConfig(), packConfig()
*/
int roc::Gpio::getConfig(uint32_t& mask)
{
return board().get(ROC_GPIO_CONFIG, mask);
}
//----------------------------------------------------------------------------
//! Write GPIO configuration register.
/*!
* \param mask new content of the GPIO configuration register
* \returns see \ref roc_board_opererr
* \sa getConfig(), unpackConfig(), packConfig()
*/
int roc::Gpio::setConfig(uint32_t mask)
{
return board().put(ROC_GPIO_CONFIG, mask);
}
//----------------------------------------------------------------------------
//! Configure one GPIO port.
/*!
* \param gpio_nr The number of the GPIO port (2 - 7 for SYNC_S0, SYNC_S1,
* AUX0, AUX1, AUX2, AUX3)
* \param riseedge if \c true, SYNC is enable or AUX records rising edges
* \param falledge if \c true, SYNC is enable or AUX records falling edges
* \param throttled if \c true, the channel is sensitive to throttling, data
* is dropped when ROC is throttling. If \c false, port sends data even when
* ROC is throttling.
* \param extrafunc if \c true enables additional functionality associated
* with port:
* \li for SYNC_S0: loop-back from SYNC_M
* \li for SYNC_S1: loop-back from SYNC_M
* \li for AUX2: TP_in active, ROC will send AUX2 to nXYTER TESTPULSE
* \li for AUX3: THR_in active, ROC will throttle when AUX3=1
* \param altin if \c true, switches an AUX to an alternate input source:
* \li for AUX1: PULSER_ACTIVE (test pulse generator monitor)
* \li for AUX3: THROTTLE_OUT (throttle loopback)
* \returns see \ref roc_board_opererr or -1 if gpio_nr out of range.
*
* \sa getConfig(), setConfig(), unpackConfig(),
* packConfig()
*/
int roc::Gpio::setConfig(int gpio_nr, bool riseedge, bool falledge,
bool throttled, bool extrafunc, bool altin)
{
uint32_t mask;
int rc = getConfig(mask);
if (rc) return rc;
if (!packConfig(mask, gpio_nr, riseedge, falledge, throttled,
extrafunc, altin)) return -1;
rc = setConfig(mask);
if (rc) Board::operErrBuildInc(rc,1);
return 0;
}
//----------------------------------------------------------------------------
//! Update part of GPIO configuration mask.
/*!
* Updates in the GPIO configuration mask \a mask the bits corresponding to
* GPIO port \a gpio_nr accoding to the attributes \a riseedge, \a falledge,
* \a throttled, \a extrafunc and \a altin.
* For detailed description of attributes see setRocGpioConfig().
* Unsupported attributes are ignored. Returns \c false if gpio_nr is
* outside range 2 to 7.
*/
bool roc::Gpio::packConfig(uint32_t& mask, int gpio_nr,
bool riseedge, bool falledge,
bool throttled, bool extrafunc,
bool altin)
{
if (gpio_nr <2 || gpio_nr>7) return false;
if (gpio_nr==2 || gpio_nr==3) { // SYNC
riseedge = riseedge | falledge;
falledge = false;
}
mask = mask & (~(0xf<<(4*gpio_nr)));
uint32_t submask = 0;
if (riseedge) submask |= 0x1;
if (falledge) submask |= 0x2;
if (throttled) submask |= 0x4;
if (extrafunc) submask |= 0x8;
mask = mask | ( submask << (4*gpio_nr));
if (gpio_nr >= 4) { // AUX
uint32_t bitmask = 1<<(gpio_nr-4);
mask = mask & (~bitmask);
if (altin) mask |= bitmask;
}
return true;
}
//----------------------------------------------------------------------------
//! Retrieve attribute flags from GPIO configuration mask.
/*!
* Retrieves from the GPIO configuration mask \a mask the bits corresponding to
* GPIO port \a gpio_nr accoding to the attributes \a riseedge, \a falledge,
* \a throttled, \a extrafunc and \a altin.
* For detailed description of attributes see setRocGpioConfig().
* Returns \c false if gpio_nr is outside range 2 to 7.
*/
bool roc::Gpio::unpackConfig(uint32_t mask, int gpio_nr,
bool& riseedge, bool& falledge,
bool& throttled, bool& extrafunc,
bool& altin)
{
if (gpio_nr <2 || gpio_nr>7) return false;
uint32_t submask = (mask >> (4*gpio_nr)) & 0xf;
riseedge = (submask & 0x1) != 0;
falledge = (submask & 0x2) != 0;
throttled = (submask & 0x4) != 0;
extrafunc = (submask & 0x8) != 0;
if ((gpio_nr==2)||(gpio_nr==3)) {
riseedge = riseedge | falledge;
falledge = false;
}
altin = false;
if (gpio_nr >= 4) { // AUX
uint32_t bitmask = 1<<(gpio_nr-4);
altin = (mask & bitmask) != 0;
}
return true;
}
//----------------------------------------------------------------------------
//! Add the GPIO interface address set to the address mapping tables.
void roc::Gpio::addAddrMap(roc::Board* board)
{
board->addRocAddrMapping("ROC_SYNC1_SCALEDOWN", ROC_SYNC1_SCALEDOWN);
board->addRocAddrMapping("ROC_SYNC1_BAUD_START", ROC_SYNC1_BAUD_START);
board->addRocAddrMapping("ROC_SYNC1_BAUD1", ROC_SYNC1_BAUD1);
board->addRocAddrMapping("ROC_SYNC1_BAUD2", ROC_SYNC1_BAUD2);
board->addRocAddrMapping("ROC_SYNC2_BAUD_START", ROC_SYNC2_BAUD_START);
board->addRocAddrMapping("ROC_SYNC2_BAUD1", ROC_SYNC2_BAUD1);
board->addRocAddrMapping("ROC_SYNC2_BAUD2", ROC_SYNC2_BAUD2);
board->addRocAddrMapping("ROC_SYNC3_BAUD_START", ROC_SYNC3_BAUD_START);
board->addRocAddrMapping("ROC_SYNC3_BAUD1", ROC_SYNC3_BAUD1);
board->addRocAddrMapping("ROC_SYNC3_BAUD2", ROC_SYNC3_BAUD2);
board->addRocAddrMapping("ROC_GPIO_CONFIG", ROC_GPIO_CONFIG);
}
//----------------------------------------------------------------------------
const char* roc::Gpio::name(int n)
{
static const char* gpio_names[NumGpio] = { "SYNC_M", "SYNC_S0", "SYNC_S1", "AUX0", "AUX1", "AUX2", "AUX3" };
if ((n<0) || (n>=NumGpio)) return 0;
return gpio_names[n];
}