diff --git a/src/include/drv/daqLib.c b/src/include/drv/daqLib.c index 8e1536f098fe5ba7a0506e9d4dd21d171a967e51..290b17f17692447385d50898a9cdb0e7c9a7c1e4 100644 --- a/src/include/drv/daqLib.c +++ b/src/include/drv/daqLib.c @@ -1,39 +1,35 @@ -/// @file daqLib.c -/// @brief This module provides the generic routines for: \n -///< - Writing DAQ, GDS TP and GDS EXC signals to the -///< Framebuilder. \n -///< - Reading GDS EXC signals from shmem and writing them -///< to the requested front end code exc channels. +/*! \file daqLib.c + * \brief File contains routines to support DAQ on realtime systems. \n + * \author R.Bork, A. Ivanov +*/ volatile DAQ_INFO_BLOCK *pInfo; ///< Ptr to DAQ config in shmem. - extern volatile char *_epics_shm; ///< Ptr to EPICS shmem block extern long daqBuffer; ///< Address of daqLib swing buffers. extern char *_daq_shm; ///< Pointer to DAQ base address in shared memory. struct rmIpcStr *dipc; ///< Pointer to DAQ IPC data in shared memory. struct cdsDaqNetGdsTpNum *tpPtr; ///< Pointer to TP table in shared memory. char *mcPtr; ///< Pointer to current DAQ data in shared memory. -float *testPtr; ///< Pointer to current DAQ data in shared memory. -char *testPtrI; ///< Pointer to current DAQ data in shared memory. -char *readPtrI; char *lmPtr; ///< Pointer to current DAQ data in local memory data buffer. char *daqShmPtr; ///< Pointer to DAQ data in shared memory. int fillSize; ///< Amount of data to copy local to shared memory. -char *pEpicsIntData; -char *pEpicsDblData; +char *pEpicsIntData; ///< Pointer to EPICS integer type data in shared memory. +char *pEpicsDblData; ///< Pointer to EPICS double type data in shared memory. +unsigned int curDaqBlockSize; ///< Total DAQ data rate diag +// Added to get EPICS data for RCG V2.8 +char *pEpicsInt; // Pointer to current DAQ data in shared memory. +char *pEpicsInt1; +float *pEpicsFloat; // Pointer to current DAQ data in shared memory. double *pEpicsDblData1; -unsigned int curDaqBlockSize; /* ******************************************************************** */ /* Routine to connect and write to LIGO DAQ system */ /* ******************************************************************** */ -/// @brief This function provides for reading GDS TP/EXC and writing DAQ data. -///< For DAQ data, this routine also provides all necessary decimation filtering. - -/// For additional information in LIGO DCC, see -/// <a href="https://dcc.ligo.org/cgi-bin/private/DocDB/ShowDocument?docid=8037">T0900638 CDS Real-time DAQ Software</a> -/// @param[in] flag Initialization flag +/// @author R.Bork, A. Ivanov\n +/// @brief This function provides for reading GDS TP/EXC and writing DAQ data. \n +/// @detail For additional information in LIGO DCC, see <a href="https://dcc.ligo.org/cgi-bin/private/DocDB/ShowDocument?docid=8037">T0900638 CDS Real-time DAQ Software</a> +/// @param[in] flag Initialization flag (1=Init call, 0 = run) /// @param[in] dcuId DAQ Data unit ID - unique within a control system /// @param[in] daqRange Struct defining fron end valid test point and exc ranges. /// @param[in] sysRate Data rate of the code / 16 @@ -61,13 +57,9 @@ double dWord; /* Temp value for storage of DAQ values */ static int daqBlockNum; /* 1-16, tracks DAQ block to write to. */ static int excBlockNum; /* 1-16, tracks EXC block to read from. */ static int excDataSize; -static int xferSize; /* Tracks remaining xfer size for crc */ -static int xferSize1; -static int mnDaqSize; -static int xferLength; +static DAQ_XFER_INFO xferInfo; static int xferDone; -static int crcLength; /* Number of bytes in 1/16 sec data */ -static char *pDaqBuffer[2]; /* Pointers to local swing buffers. */ +static char *pDaqBuffer[DAQ_NUM_SWING_BUFFERS]; /* Pointers to local swing buffers. */ static DAQ_LKUP_TABLE localTable[DCU_MAX_CHANNELS]; static DAQ_LKUP_TABLE excTable[DCU_MAX_CHANNELS]; static char *pWriteBuffer; /* Ptr to swing buff to write data */ @@ -75,9 +67,6 @@ static char *pReadBuffer; /* Ptr to swing buff to xmit data to FB */ static int phase; /* 0-1, switches swing buffers. */ static int daqSlot; /* 0-sysRate, data slot to write data */ static int excSlot; /* 0-sysRate, slot to read exc data */ -static int daqWaitCycle; /* If 0, write to FB (256Hz) */ -static int daqWriteTime; /* Num daq cycles between writes. */ -static int daqWriteCycle; /* Cycle count to xmit to FB. */ float *pFloat = 0; /* Temp ptr to write float data. */ short *pShort = 0; /* Temp ptr to write short data. */ unsigned int *pInteger = 0; /* Temp ptr to write unsigned int data. */ @@ -85,11 +74,9 @@ char *bufPtr; /* Ptr to data for crc calculation. */ static unsigned int crcTest; /* Continuous calc of CRC. */ static unsigned int crcSend; /* CRC sent to FB. */ static DAQ_INFO_BLOCK dataInfo; /* Local DAQ config info buffer. */ -static UINT32 fileCrc; /* .ini file CRC, sent to FB. */ int decSlot; /* Tracks decimated data positions. */ -int offsetAccum; /* Used to set localTable.offset */ static int tpStart; /* Marks address of first TP data */ -static volatile GDS_CNTRL_BLOCK *gdsPtr; /* Ptr to GDS table in shmem. */ +static volatile GDS_CNTRL_BLOCK *gdsPtr; /* Ptr to shm to pass TP info to DAQ */ static volatile char *exciteDataPtr; /* Ptr to EXC data in shmem. */ static int validTp = 0; /* Number of valid GDS sigs selected. */ static int validTpNet = 0; /* Number of valid GDS sigs selected. */ @@ -97,8 +84,6 @@ static int validEx; /* EXC signal set status indicator. */ static int tpNum[DAQ_GDS_MAX_TP_ALLOWED]; /* TP/EXC selects to send to FB. */ static int tpNumNet[DAQ_GDS_MAX_TP_ALLOWED]; /* TP/EXC selects to send to FB. */ static int totalChans; /* DAQ + TP + EXC chans selected. */ -static int totalSize; /* DAQ + TP + EXC chans size in bytes. */ -static int totalSizeNet; /* DAQ + TP + EXC chans size in bytes sent to network driver. */ int *statusPtr; volatile float *dataPtr; /* Ptr to excitation chan data. */ int exChanOffset; /* shmem offset to next EXC value. */ @@ -110,7 +95,8 @@ unsigned int exc; unsigned int tpn; int slot; int num_tps; -static int epicsIntXferSize; +unsigned int tpnum[DAQ_GDS_MAX_TP_ALLOWED]; // Current TP nums +unsigned int excnum[DAQ_GDS_MAX_TP_ALLOWED]; // Current EXC nums #ifdef CORE_BIQUAD // Decimation filter coefficient definitions. @@ -205,6 +191,7 @@ static double dHistory[DCU_MAX_CHANNELS][MAX_HISTRY]; // ************************************************************************************** +/// If flag input is 1, then this is a startup initialization request from controller code. if(flag == DAQ_CONNECT) /* Initialize DAQ connection */ { @@ -213,238 +200,53 @@ static double dHistory[DCU_MAX_CHANNELS][MAX_HISTRY]; daqBlockNum = (DAQ_NUM_DATA_BLOCKS - 1); excBlockNum = 0; - /* Allocate memory for two local data swing buffers */ - for(ii=0;ii<2;ii++) + /// ** INITIALIZATION **************\n + /// \> Two local memory swing buffers will be used to store acquired data, each containing + /// 1/16 sec of data.\n + /// ---- One for writing ie copying/filtering data from shared memory on each cycle. \n + /// ---- One for reading data ie copying data from local memory to memory shared with + /// DAQ network communication software. \n + /// \> Buffers switch roles every 1/16 sec. \n + /// \> Introduces 1/16 sec delay on delivery of data to network. However, this is done for + /// performance reasons ie it takes too long to perform CRC checksum on full data set and + /// to get the data out. With this method, the computing load can be spread out on a per + /// per cycle basis. \n + /// \>\> Allocate memory for two local data swing buffers + for(ii=0;ii<DAQ_NUM_SWING_BUFFERS;ii++) { pDaqBuffer[ii] = (char *)daqBuffer; pDaqBuffer[ii] += DAQ_DCU_SIZE * ii; - // printf("DAQ buffer %d is at 0x%x\n",ii,(long long)pDaqBuffer[ii]); } - - // Clear the decimation filter histories - for(ii=0;ii<DCU_MAX_CHANNELS;ii++) - for(jj=0;jj<MAX_HISTRY;jj++) - dHistory[ii][jj] = 0.0; - - /* Set pointers to two swing buffers */ + /// \>\> Set pointers to two swing buffers pWriteBuffer = (char *)pDaqBuffer[phase^1]; pReadBuffer = (char *)pDaqBuffer[phase]; daqSlot = -1; excSlot = 0; + /// \> CDS standard IIR filters will be used for decimation filtering from + /// the native application rate down to DAQ sample rate. \n + /// \>\> Need to clear the decimation filter histories. + for(ii=0;ii<DCU_MAX_CHANNELS;ii++) + for(jj=0;jj<MAX_HISTRY;jj++) + dHistory[ii][jj] = 0.0; + + /// \> Setup Pointers to the various shared memories:\n + /// ---- Assign Ptr to data shared memory to network driver (mx_stream) \n daqShmPtr = _daq_shm + CDS_DAQ_NET_DATA_OFFSET; - buf_size = DAQ_DCU_BLOCK_SIZE*2; + buf_size = DAQ_DCU_BLOCK_SIZE*DAQ_NUM_SWING_BUFFERS; + /// ---- Setup Ptr to interprocess comms with network driver dipc = (struct rmIpcStr *)(_daq_shm + CDS_DAQ_NET_IPC_OFFSET); + /// ---- Setup Ptr to awgtpman shared memory (TP number table) tpPtr = (struct cdsDaqNetGdsTpNum *)(_daq_shm + CDS_DAQ_NET_GDS_TP_TABLE_OFFSET); - mcPtr = daqShmPtr; - lmPtr = pReadBuffer; - fillSize = DAQ_DCU_BLOCK_SIZE / sysRate; - printf("DIRECT MEMORY MODE of size %d\n",fillSize); + mcPtr = daqShmPtr; // Set daq2net data ptr to start of daq2net shared memory. + lmPtr = pReadBuffer; // Set read buffer ptr to start of read buffer.. - - crcLength = 0; - printf("daqLib DCU_ID = %d\n",dcuId); - - /* Set up pointer to DAQ configuration information in shmem */ + // Set mem cpy size evenly over all code cycles. + fillSize = DAQ_DCU_BLOCK_SIZE / sysRate; + /// ---- Set up pointer to DAQ configuration information in shmem */ pInfo = (DAQ_INFO_BLOCK *)(_epics_shm + DAQ_INFO_ADDRESS); - - // Setup EPICS channel information/pointers - dataInfo.numEpicsInts = pInfo->numEpicsInts; - dataInfo.numEpicsFloats = pInfo->numEpicsFloats; - dataInfo.numEpicsFilts = pInfo->numEpicsFilts; - dataInfo.numEpicsTotal = pInfo->numEpicsTotal; - pEpicsIntData = pEpics; - epicsIntXferSize = dataInfo.numEpicsInts * 4; - - dataInfo.epicsdblDataOffset = 0; - dataInfo.cpyepics2times = 0; - dataInfo.cpyIntSize[0] = dataInfo.numEpicsInts * 4; - dataInfo.cpyIntSize[1] = 0; - - - ii = (sizeof(CDS_EPICS_OUT) / 4); - jj = dataInfo.numEpicsInts - ii; - printf("Have %d CDS epics integer and %d USR epics integer channels\n",ii,jj); - ii *= 4; - jj *= 4; - - // Look for memory holes ie integer types not ending on 8 byte boundary. - // Need to check both standard CDS struct and User channels - // If either doesn't end on 8 byte boundary, then a 4 byte hole will appear - // before the double type data in shared memory. - if((ii % 8) || (jj % 8)) { - printf("Have at least 1 int mem hole %d %d \n",ii,jj); - dataInfo.epicsdblDataOffset = 4; - } - if ((ii%8) &&(jj>0)) { // If standard CDS struct doesn't end on 8 byte boundary, then - // Have 4 byte mem hole after CDS data - // This will require 2 memcpys of integer data to get 8 byte alignment for xfer to DAQ buffer.. - dataInfo.cpyIntSize[0] = ii; - dataInfo.cpyIntSize[1] = jj; - dataInfo.cpyepics2times = 1; - dataInfo.epicsdblDataOffset += 4; - printf("Have 2 mem holes %d %d \nNeet to cpy ints twice - size 1 = %d size 2 = %d \n",ii,jj,dataInfo.cpyIntSize[0],dataInfo.cpyIntSize[1]); - } - - // Set the pointer to start of EPICS double type data in shared memory. - pEpicsDblData = (pEpicsIntData + epicsIntXferSize + dataInfo.epicsdblDataOffset); - - // Send diags to dmesg - printf("DAQ DATA INFO is at 0x%x\n",(long)pInfo); - printf("DAQ EPICS INT DATA is at 0x%x with size %d\n",(long)pEpicsIntData,epicsIntXferSize); - printf("DAQ EPICS FLT DATA is at 0x%x\n",(long)pEpicsDblData); - - - /* Get the .INI file crc checksum to pass to DAQ Framebuilders for config checking */ - fileCrc = pInfo->configFileCRC; - // Clear the reconfiguration flag in shmem. - pInfo->reconfig = 0; - /* Get the number of channels to be acquired */ - dataInfo.numChans = pInfo->numChans; - printf("EPICS: Int = %d Flt = %d Filters = %d Total = %d Fast = %d\n",dataInfo.numEpicsInts,dataInfo.numEpicsFloats,dataInfo.numEpicsFilts, dataInfo.numEpicsTotal, dataInfo.numChans); - // Verify number of channels is legal - if((dataInfo.numChans < 1) || (dataInfo.numChans > DCU_MAX_CHANNELS)) - { - printf("Invalid num daq chans = %d\n",dataInfo.numChans); - return(-1); - } - - // Initialize CRC length with EPICS data size. - crcLength = 4 * dataInfo.numEpicsTotal; -printf("crc length epics = %d\n",crcLength); - - /* Get the DAQ configuration information for all channels and calc a crc checksum length */ - for(ii=0;ii<dataInfo.numChans;ii++) - { - dataInfo.tp[ii].tpnum = pInfo->tp[ii].tpnum; - dataInfo.tp[ii].dataType = pInfo->tp[ii].dataType; - dataInfo.tp[ii].dataRate = pInfo->tp[ii].dataRate; - if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) - crcLength += 2 * dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS; - else - crcLength += 4 * dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS; - } - - /* Calculate the number of bytes to xfer on each call, based on total number - of bytes to write each 1/16sec and the front end data rate (2048/16384Hz) */ - // Note, this is left over from RFM net. Now used only to calc CRC - xferSize1 = crcLength/sysRate; - // mnDaqSize = crcLength/DAQ_NUM_DATA_BLOCKS; - mnDaqSize = crcLength; - // curDaqBlockSize = mnDaqSize * 256; - curDaqBlockSize = crcLength * DAQ_NUM_DATA_BLOCKS_PER_SECOND; - totalSize = crcLength; - totalSizeNet = crcLength; - -printf (" xfer sizes = %d %d %d %d \n",sysRate,xferSize1,totalSize,crcLength); - - if (xferSize1 == 0) { - printf("DAQ size too small\n"); - return -1; - } -/* if (xferSize1 == 0) xferSize1 = 8; ???? */ - - /* Maintain 8 byte data boundaries for writing data, particularly important - when DMA xfers are used on 5565 RFM modules. Note that this usually results - in data not being written on every 2048/16384 cycle and last data xfer - in a 1/16 sec block well may be shorter than the rest. */ - xferSize1 = ((xferSize1/8) + 1) * 8; - printf("DAQ resized %d\n", xferSize1); - - - - // Fill in the local lookup table for finding data. - // offsetAccum = 0; - offsetAccum = 4 * dataInfo.numEpicsTotal; - localTable[0].offset = offsetAccum; - -printf("Fast data offset = %d \n",offsetAccum); - - for(ii=0;ii<dataInfo.numChans;ii++) - { - /* Need to develop a table of offset pointers to load data into swing buffers */ - /* This is based on decimation factors and data size */ - if ((dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS) > sysRate) { - /* Channel data rate is greater than system rate */ - printf("Channels %d has bad data rate %d\n", ii, dataInfo.tp[ii].dataRate); - return(-1); - } else { - localTable[ii].decFactor = sysRate/(dataInfo.tp[ii].dataRate / 16); - } - if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) - offsetAccum += (sysRate/localTable[ii].decFactor * 2); - else - offsetAccum += (sysRate/localTable[ii].decFactor * 4); - localTable[ii+1].offset = offsetAccum; - /* Need to determine if data is from a filter module TP or non-FM TP */ - if((dataInfo.tp[ii].tpnum >= daqRange.filtTpMin) && - (dataInfo.tp[ii].tpnum < daqRange.filtTpMax)) - /* This is a filter module testpoint */ - { - jj = dataInfo.tp[ii].tpnum - daqRange.filtTpMin; - /* Mark as coming from a filter module testpoint */ - localTable[ii].type = 0; - /* Mark which system filter module is in */ - localTable[ii].sysNum = jj / daqRange.filtTpSize; - jj -= localTable[ii].sysNum * daqRange.filtTpSize; - /* Mark which filter module within a system */ - localTable[ii].fmNum = jj / 3; - /* Mark which of three testpoints to store */ - localTable[ii].sigNum = jj % 3; - } - else if((dataInfo.tp[ii].tpnum >= daqRange.filtExMin) && - (dataInfo.tp[ii].tpnum < daqRange.filtExMax)) - /* This is a filter module excitation input */ - { - /* Mark as coming from a filter module excitation input */ - localTable[ii].type = 2; - /* Mark filter module number */ - localTable[ii].fmNum = dataInfo.tp[ii].tpnum - daqRange.filtExMin; - } - else if((dataInfo.tp[ii].tpnum >= daqRange.xTpMin) && - (dataInfo.tp[ii].tpnum < daqRange.xTpMax)) - /* This testpoint is not part of a filter module */ - { - jj = dataInfo.tp[ii].tpnum - daqRange.xTpMin; - /* Mark as a non filter module testpoint */ - localTable[ii].type = 1; - /* Mark the offset into the local data buffer */ - localTable[ii].sigNum = jj; - } - // :TODO: this is broken, needs some work to make extra EXC work. - else if((dataInfo.tp[ii].tpnum >= daqRange.xExMin) && - (dataInfo.tp[ii].tpnum < daqRange.xExMax)) - /* This exc testpoint is not part of a filter module */ - { - jj = dataInfo.tp[ii].tpnum - daqRange.xExMin; - /* Mark as a non filter module testpoint */ - localTable[ii].type = 3; - /* Mark the offset into the local data buffer */ - localTable[ii].fmNum = jj; - localTable[ii].sigNum = jj; - } - else - { - printf("Invalid chan num found %d = %d\n",ii,dataInfo.tp[ii].tpnum); - return(-1); - } - } - - // Set the start of TP data after DAQ data. - tpStart = offsetAccum; - totalChans = dataInfo.numChans; - // Set pointer to GDS table in shmem + /// ---- Set pointer to shared mem to pass GDS info to DAQ gdsPtr = (GDS_CNTRL_BLOCK *)(_epics_shm + DAQ_GDS_BLOCK_ADD); - // Clear out the GDS TP selections. - if (sysRate < DAQ_16K_SAMPLE_SIZE) tpx = 3; else tpx = 2; - for (ii=0; ii < DAQ_GDS_MAX_TP_ALLOWED; ii++) gdsPtr->tp[tpx][0][ii] = 0; - if(sysRate < DAQ_16K_SAMPLE_SIZE) tpx = 1; else tpx = 0; - for (ii=0; ii < DAQ_GDS_MAX_TP_ALLOWED; ii++) gdsPtr->tp[tpx][0][ii] = 0; - // Following can be uncommented for testing. - // gdsPtr->tp[3][0][0] = 31250; - // gdsPtr->tp[3][0][1] = 11002; - // gdsPtr->tp[0][0][0] = 5000; - // Set pointer to EXC data in shmem. if(sysRate < DAQ_16K_SAMPLE_SIZE) { @@ -455,26 +257,29 @@ printf("Fast data offset = %d \n",offsetAccum); } excDataSize = 4 + 4 * sysRate; - // Following just sets in some dummy data for testing. - for(ii=0;ii<16;ii++) - { - statusPtr = (int *)(exciteDataPtr + ii * DAQ_DCU_BLOCK_SIZE); - *statusPtr = 0; - dataPtr = (float *)(exciteDataPtr + ii * DAQ_DCU_BLOCK_SIZE + 4); - for(jj=0;jj<1024;jj++) - { - *dataPtr = (float)(ii * 1000 + jj); - dataPtr ++; - } - } + // Clear the reconfiguration flag in shmem. + pInfo->reconfig = 0; + + // Configure data channels ***************************************************** + // Return error if configuration is incorrect. + /// \> Load DAQ configuration info from memory shared with EPICS + if((xferInfo.crcLength = daqConfig(&dataInfo,pInfo,pEpics)) == -1) return(-1); - // Initialize network variables. - daqWaitCycle = -1; - daqWriteCycle = 0; - daqWriteTime = sysRate / 16; + /// \> Load local table information with channel info + if((status = loadLocalTable(&xferInfo,localTable,sysRate,&dataInfo,&daqRange)) == -1) return(-1); + // Set the start of TP data after DAQ data. + tpStart = xferInfo.offsetAccum; + totalChans = dataInfo.numChans; + /// \> Clear out the GDS TP selections. + if (sysRate < DAQ_16K_SAMPLE_SIZE) tpx = 3; else tpx = 2; + for (ii=0; ii < DAQ_GDS_MAX_TP_ALLOWED; ii++) gdsPtr->tp[tpx][0][ii] = 0; + if(sysRate < DAQ_16K_SAMPLE_SIZE) tpx = 1; else tpx = 0; + for (ii=0; ii < DAQ_GDS_MAX_TP_ALLOWED; ii++) gdsPtr->tp[tpx][0][ii] = 0; + + /// \> Clear the GDS TP lookup table for (i = 0; i < DAQ_GDS_MAX_TP_ALLOWED; i++) { tpNum[i] = 0; tpNumNet[i] = 0; @@ -483,42 +288,42 @@ printf("Fast data offset = %d \n",offsetAccum); validTpNet = 0; //printf("at connect TPnum[0]=%d\n", tpNum[0]); - } /* End DAQ CONNECT */ + } /// End DAQ CONNECT INITIALIZATION ****************************** /* ******************************************************************************** */ /* Write Data to FB ******************************************* */ /* ******************************************************************************** */ +/// If flag=0, data is to be acquired. This is called every code cycle by controller.c +/// ** Data Acquisition Mode ******************************************************** if(flag == DAQ_WRITE) { - /* Calc data offset into swing buffer */ + /// \> Calc data offset into current write swing buffer daqSlot = (daqSlot + 1) % sysRate; - daqWaitCycle = (daqWaitCycle + 1) % daqWriteTime; - /* At start of 1/16 sec. data block, reset the xfer sizes and done bit */ + /// \> At start of 1/16 sec. data block, reset the xfer sizes and done bit */ if(daqSlot == 0) { - xferLength = crcLength; - xferSize = xferSize1; + xferInfo.xferLength = xferInfo.crcLength; + xferInfo.xferSize = xferInfo.xferSize1; xferDone = 0; - //printf("TPnum[0]=%d\n", tpNum[0]); } - /* If size of data remaining to be sent is less than calc xfer size, reduce xfer size - to that of data remaining and mark that data xfer is complete for this 1/16 sec block */ - if((xferLength < xferSize1) && (!xferDone)) + /// \> If size of data remaining to be sent is less than calc xfer size, reduce xfer size + /// to that of data remaining and mark that data xfer is complete for this 1/16 sec block + if((xferInfo.xferLength < xferInfo.xferSize1) && (!xferDone)) { - xferSize = xferLength; - if(xferSize <= 0) xferDone = 1; + xferInfo.xferSize = xferInfo.xferLength; + if(xferInfo.xferSize <= 0) xferDone = 1; } - /* Write data into local swing buffer */ + /// \> Write data into local swing buffer for(ii=0;ii<totalChans;ii++) { dWord = 0; - /* Read in the data to a local variable, either from a FM TP or other TP */ + /// \> Read data to a local variable, either from a FM TP or other TP */ if(localTable[ii].type == DAQ_SRC_FM_TP) /* Data if from filter module testpoint */ { @@ -552,7 +357,7 @@ printf("Fast data offset = %d \n",offsetAccum); dWord = excSignal[localTable[ii].fmNum]; } - // Perform decimation filtering, if required. + /// \> Perform decimation filtering, if required. #ifdef CORE_BIQUAD #define iir_filter iir_filter_biquad #endif @@ -571,7 +376,7 @@ printf("Fast data offset = %d \n",offsetAccum); #undef iir_filter #endif - // Write the data into the swing buffer. + /// \> Write fast data into the swing buffer. if ((daqSlot % localTable[ii].decFactor) == 0) { if (dataInfo.tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) { // Write short data; (XOR 1) here provides sample swapping @@ -595,86 +400,92 @@ printf("Fast data offset = %d \n",offsetAccum); } } /* end swing buffer write loop */ - // Copy data from read buffer to shared memory - memcpy(mcPtr,lmPtr,fillSize); - mcPtr += fillSize; - lmPtr += fillSize; - +/// \> Write EPICS data into swing buffer at 16Hz. if(daqSlot == 0) { -// Write EPICS integer values +/// \>\> On 16Hz boundary: \n +/// - ---- Write EPICS integer values to beginning of local write buffer if(dataInfo.cpyepics2times) { memcpy(pWriteBuffer,pEpicsIntData,dataInfo.cpyIntSize[0]); - testPtrI = pWriteBuffer; - testPtrI += dataInfo.cpyIntSize[0]; - readPtrI = pEpicsIntData + dataInfo.cpyIntSize[0] + 4; - memcpy(testPtrI,readPtrI,dataInfo.cpyIntSize[1]); + pEpicsInt = pWriteBuffer; + pEpicsInt += dataInfo.cpyIntSize[0]; + pEpicsInt1 = pEpicsIntData + dataInfo.cpyIntSize[0] + 4; + memcpy(pEpicsInt,pEpicsInt1,dataInfo.cpyIntSize[1]); } else { memcpy(pWriteBuffer,pEpicsIntData,dataInfo.cpyIntSize[0]); } -} -if(daqSlot == 0) -{ -// Write EPICS double values as float values +/// - ---- Write EPICS double values as float values after EPICS integer type data. pEpicsDblData1 = (double *)pEpicsDblData; - testPtr = (float *)pWriteBuffer; - testPtr += dataInfo.numEpicsInts; + pEpicsFloat = (float *)pWriteBuffer; + pEpicsFloat += dataInfo.numEpicsInts; for(ii=0;ii<dataInfo.numEpicsFloats;ii++) { - *testPtr = (float)*pEpicsDblData1; - testPtr ++; + *pEpicsFloat = (float)*pEpicsDblData1; + pEpicsFloat ++; pEpicsDblData1 ++; } } if(daqSlot == 1) { -// Write filter module EPICS values as floats +/// \>\> On 16Hz boundary + 1 cycle: \n +/// - ---- Write filter module EPICS values as floats for(ii=0;ii<MAX_MODULES;ii++) { - *testPtr = (float)dspPtr->inputs[ii].offset;; - testPtr ++; - *testPtr = (float)dspPtr->inputs[ii].outgain;; - testPtr ++; - *testPtr = (float)dspPtr->inputs[ii].limiter;; - testPtr ++; - *testPtr = (float)dspPtr->inputs[ii].gain_ramp_time;; - testPtr ++; - *testPtr = (float)dspPtr->inputs[ii].swReq;; - testPtr ++; - *testPtr = (float)dspPtr->inputs[ii].swMask;; - testPtr ++; - *testPtr = (float)dspPtr->data[ii].filterInput;; - testPtr ++; - *testPtr = (float)dspPtr->data[ii].exciteInput;; - testPtr ++; - *testPtr = (float)dspPtr->data[ii].output16Hz;; - testPtr ++; - *testPtr = (float)dspPtr->data[ii].output;; - testPtr ++; - *testPtr = (float)dspPtr->data[ii].swStatus;; - testPtr ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].offset; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].outgain;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].limiter;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].gain_ramp_time;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].swReq;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->inputs[ii].swMask;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->data[ii].filterInput;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->data[ii].exciteInput;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->data[ii].output16Hz;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->data[ii].output;; + pEpicsFloat ++; + *pEpicsFloat = (float)dspPtr->data[ii].swStatus;; + pEpicsFloat ++; } } + + /// \> Copy data from read buffer to DAQ network shared memory on each code cycle. + /// - ---- Entire buffer is moved during 1/16sec period, in equal amounts each cycle, even though + /// entire buffer is not full of data. + memcpy(mcPtr,lmPtr,fillSize); + mcPtr += fillSize; + lmPtr += fillSize; + + /// - ---- Perform CRC checksum on data moved from read buffer to DAQ network shared memory. if(!xferDone) { /* Do CRC check sum calculation */ - bufPtr = (char *)pReadBuffer + daqSlot * xferSize1; - if(daqSlot == 0) crcTest = crc_ptr(bufPtr, xferSize, 0); - else crcTest = crc_ptr(bufPtr, xferSize, crcTest); - xferLength -= xferSize; + bufPtr = (char *)pReadBuffer + daqSlot * xferInfo.xferSize1; + if(daqSlot == 0) crcTest = crc_ptr(bufPtr, xferInfo.xferSize, 0); + else crcTest = crc_ptr(bufPtr, xferInfo.xferSize, crcTest); + xferInfo.xferLength -= xferInfo.xferSize; } if(daqSlot == (sysRate - 1)) /* Done with 1/16 second data block */ { /* Complete CRC checksum calc */ - crcTest = crc_len(crcLength, crcTest); + crcTest = crc_len(xferInfo.crcLength, crcTest); crcSend = crcTest; } - // Read in any selected EXC signals. + /// \> Read in any selected EXC signals. \n + /// --- NOTE: EXC signals have to be read and loaded in advance by 1 cycle ie must be loaded and + /// available to the realtime application when the next code cycle is initiated. excSlot = (excSlot + 1) % sysRate; //if(validEx) validEx = 0; @@ -683,7 +494,7 @@ if(daqSlot == 1) for(ii=dataInfo.numChans;ii<totalChans;ii++) { // Do not pickup any testpoints (type 0 or 1) - if (localTable[ii].type < 2) continue; + if (localTable[ii].type < DAQ_SRC_FM_EXC) continue; exChanOffset = localTable[ii].sigNum * excDataSize; statusPtr = (int *)(exciteDataPtr + excBlockNum * DAQ_DCU_BLOCK_SIZE + exChanOffset); @@ -704,208 +515,80 @@ if(daqSlot == 1) } } - // Move to the next 1/16 EXC signal data block - if(excSlot == (sysRate - 1)) excBlockNum = (excBlockNum + 1) % 16; + /// \> Move to the next 1/16 EXC signal data block if end of 16Hz block + if(excSlot == (sysRate - 1)) excBlockNum = (excBlockNum + 1) % DAQ_NUM_DATA_BLOCKS; + /// \> If last cycle of a 16Hz block: if(daqSlot == (sysRate - 1)) /* Done with 1/16 second DAQ data block */ { - /* Swap swing buffers */ - phase = (phase + 1) % 2; + /// - -- Swap swing buffers + phase = (phase + 1) % DAQ_NUM_SWING_BUFFERS; pReadBuffer = (char *)pDaqBuffer[phase]; pWriteBuffer = (char *)pDaqBuffer[(phase^1)]; -// Assign global parameters - dipc->dcuId = dcuId; // DCU id of this system - dipc->crc = fileCrc; // Checksum of the configuration file - // dipc->dataBlockSize = crcLength; // actual data size - dipc->dataBlockSize = totalSizeNet * DAQ_NUM_DATA_BLOCKS_PER_SECOND; // actual data size - // Assign current block parameters + /// - -- Fill in the IPC table for DAQ network driver (mx_stream) \n + dipc->dcuId = dcuId; /// - ------ DCU id of this system + dipc->crc = xferInfo.fileCrc; /// - ------ Checksum of the configuration file + dipc->dataBlockSize = xferInfo.totalSizeNet * DAQ_NUM_DATA_BLOCKS_PER_SECOND; /// - ------ Actual data size + /// - ------ Data block number dipc->bp[daqBlockNum].cycle = daqBlockNum; + /// - ------ Data block CRC dipc->bp[daqBlockNum].crc = crcSend; - //ipc->bp[daqBlockNum].status = 0; + /// - ------ Timestamp GPS Second if (daqBlockNum == DAQ_NUM_DATA_BLOCKS_PER_SECOND - 1) { dipc->bp[daqBlockNum].timeSec = ((unsigned int) cycle_gps_time - 1); } else { dipc->bp[daqBlockNum].timeSec = (unsigned int) cycle_gps_time; } + /// - ------ Timestamp GPS nanoSecond dipc->bp[daqBlockNum].timeNSec = (unsigned int)daqBlockNum; - // Assign the test points table + /// - ------ Write test point info to DAQ net shared memory tpPtr->count = validTpNet | validEx; memcpy(tpPtr->tpNum, tpNumNet, sizeof(tpNumNet[0]) * validTp); // As the last step set the cycle counter // Frame builder is looking for cycle change + /// - ------ Write IPC cycle number. This will trigger DAQ network driver to send data to DAQ dipc->cycle =daqBlockNum; // Ready cycle (16 Hz) - /* Increment the 1/16 sec block counter */ + /// - -- Increment the 1/16 sec block counter daqBlockNum = (daqBlockNum + 1) % DAQ_NUM_DATA_BLOCKS_PER_SECOND; + /// - -- Reset pointers to DAQ net shared memory and local read buffer. mcPtr = daqShmPtr; mcPtr += buf_size * daqBlockNum; lmPtr = pReadBuffer; - // Check for reconfig request at start of each second + /// - -- Check for reconfig request at start of each second if((pInfo->reconfig == 1) && (daqBlockNum == 0)) { printf("New daq config\n"); - status = pInfo->numChans; pInfo->reconfig = 0; - if((status > 0) && (status <= DCU_MAX_CHANNELS)) + // Configure EPICS data channels + xferInfo.crcLength = daqConfig(&dataInfo,pInfo,pEpics); + if(xferInfo.crcLength) { - /* Get the .INI file crc checksum to pass to DAQ Framebuilders for config checking */ - fileCrc = pInfo->configFileCRC; - /* Get the number of channels to be acquired */ - dataInfo.numChans = pInfo->numChans; - crcLength = 0; - - // Setup EPICS channel information/pointers - dataInfo.numEpicsInts = pInfo->numEpicsInts; - dataInfo.numEpicsFloats = pInfo->numEpicsFloats; - dataInfo.numEpicsFilts = pInfo->numEpicsFilts; - dataInfo.numEpicsTotal = pInfo->numEpicsTotal; - pEpicsIntData = pEpics; - epicsIntXferSize = dataInfo.numEpicsInts * 4; - - dataInfo.epicsdblDataOffset = 0; - dataInfo.cpyepics2times = 0; - dataInfo.cpyIntSize[0] = dataInfo.numEpicsInts * 4; - dataInfo.cpyIntSize[1] = 0; - - - ii = (sizeof(CDS_EPICS_OUT) / 4); - jj = dataInfo.numEpicsInts - ii; - printf("Have %d CDS epics integer and %d USR epics integer channels\n",ii,jj); - ii *= 4; - jj *= 4; - - // Look for memory holes ie integer types not ending on 8 byte boundary. - // Need to check both standard CDS struct and User channels - // If either doesn't end on 8 byte boundary, then a 4 byte hole will appear - // before the double type data in shared memory. - if((ii%8) || (jj%8)) { - printf("Have at least 1 int mem hole %d %d \n",ii,jj); - dataInfo.epicsdblDataOffset = 4; - } - if ((ii%8) &&(jj>0)) { - // Have 4 byte mem hole after CDS data - // This will require 2 memcpys of integer data. - dataInfo.cpyIntSize[0] = ii; - dataInfo.cpyIntSize[1] = jj; - dataInfo.cpyepics2times = 1; - dataInfo.epicsdblDataOffset += 4; - printf("Have 2 mem holes %d %d \nNeet to cpy ints twice - size 1 = %d size 2 = %d \n",ii,jj,dataInfo.cpyIntSize[0] ,dataInfo.cpyIntSize[1]); - } - - // Set the pointer to start of EPICS double type data in shared memory. - pEpicsDblData = (pEpicsIntData + epicsIntXferSize + dataInfo.epicsdblDataOffset); - - printf("DAQ DATA INFO is at 0x%x\n",(long)pInfo); - printf("DAQ EPICS INT DATA is at 0x%x with size %d\n",(long)pEpicsIntData,epicsIntXferSize); - printf("DAQ EPICS FLT DATA is at 0x%x\n",(long)pEpicsDblData); - printf("EPICS: Int = %d Flt = %d Filters = %d Total = %d Fast = %d\n",dataInfo.numEpicsInts,dataInfo.numEpicsFloats,dataInfo.numEpicsFilts, dataInfo.numEpicsTotal, dataInfo.numChans); - - // Initialize CRC length with EPICS data size. - crcLength = 4 * dataInfo.numEpicsTotal; - printf("crc length epics = %d\n",crcLength); - - - /* Get the DAQ configuration information for all channels and calc a crc checksum length */ - for(ii=0;ii<dataInfo.numChans;ii++) - { - dataInfo.tp[ii].tpnum = pInfo->tp[ii].tpnum; - dataInfo.tp[ii].dataType = pInfo->tp[ii].dataType; - dataInfo.tp[ii].dataRate = pInfo->tp[ii].dataRate; - if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) - crcLength += 2 * dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS_PER_SECOND; - else - crcLength += 4 * dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS_PER_SECOND; -if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type \n"); - } - /* Calculate the number of bytes to xfer on each call, based on total number - of bytes to write each 1/16sec and the front end data rate (2048/16384Hz) */ - xferSize1 = crcLength/sysRate; - // mnDaqSize = crcLength/16; - mnDaqSize = crcLength; - totalSize = crcLength; - - /* Maintain 8 byte data boundaries for writing data, particularly important - when DMA xfers are used on 5565 RFM modules. Note that this usually results - in data not being written on every 2048/16384 cycle and last data xfer - in a 1/16 sec block well may be shorter than the rest. */ - xferSize1 = ((xferSize1/8) + 1) * 8; - - offsetAccum = 4 * pInfo->numEpicsTotal; - localTable[0].offset = offsetAccum; - + status = loadLocalTable(&xferInfo,localTable,sysRate,&dataInfo,&daqRange); + // Clear decimation filter history for(ii=0;ii<dataInfo.numChans;ii++) { - /* Need to develop a table of offset pointers to load data into swing buffers */ - /* This is based on decimation factors and data size */ - localTable[ii].decFactor = sysRate/(dataInfo.tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS_PER_SECOND); - if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) - offsetAccum += (sysRate/localTable[ii].decFactor * 2); - else - offsetAccum += (sysRate/localTable[ii].decFactor * 4); - localTable[ii+1].offset = offsetAccum; - /* Need to determine if data is from a filter module TP or non-FM TP */ - if((dataInfo.tp[ii].tpnum >= daqRange.filtTpMin) && - (dataInfo.tp[ii].tpnum < daqRange.filtTpMax)) - /* This is a filter module testpoint */ - { - jj = dataInfo.tp[ii].tpnum - daqRange.filtTpMin; - /* Mark as coming from a filter module testpoint */ - localTable[ii].type = 0; - /* Mark which system filter module is in */ - localTable[ii].sysNum = jj / daqRange.filtTpSize; - jj -= localTable[ii].sysNum * daqRange.filtTpSize; - /* Mark which filter module within a system */ - localTable[ii].fmNum = jj / DAQ_NUM_FM_TP; - /* Mark which of three testpoints to store */ - localTable[ii].sigNum = jj % DAQ_NUM_FM_TP; - } - else if((dataInfo.tp[ii].tpnum >= daqRange.filtExMin) && - (dataInfo.tp[ii].tpnum < daqRange.filtExMax)) - /* This is a filter module excitation input */ - { - /* Mark as coming from a filter module excitation input */ - localTable[ii].type = 2; - /* Mark filter module number */ - localTable[ii].fmNum = dataInfo.tp[ii].tpnum - daqRange.filtExMin; - } - else if((dataInfo.tp[ii].tpnum >= daqRange.xTpMin) && - (dataInfo.tp[ii].tpnum < daqRange.xTpMax)) - /* This testpoint is not part of a filter module */ - { - jj = dataInfo.tp[ii].tpnum - daqRange.xTpMin; - /* Mark as a non filter module testpoint */ - localTable[ii].type = 1; - /* Mark the offset into the local data buffer */ - localTable[ii].sigNum = jj; - } - else - { - printf("Invalid chan num found %d = %d\n",ii,dataInfo.tp[ii].tpnum); - return(-1); - } for(jj=0;jj<MAX_HISTRY;jj++) dHistory[ii][jj] = 0.0; } - tpStart = offsetAccum; + tpStart = xferInfo.offsetAccum; totalChans = dataInfo.numChans; } - } - // Check for new TP + } + /// - -- If last cycle of 1 sec time frame, check for new TP and load info. // This will cause new TP to be written to local memory at start of 1 sec block. if(daqBlockNum == 15) { - unsigned int tpnum[DAQ_GDS_MAX_TP_ALLOWED]; // Current TP nums - unsigned int excnum[DAQ_GDS_MAX_TP_ALLOWED]; // Current EXC nums // Offset by one into the TP/EXC tables for the 2K systems unsigned int _2k_sys_offs = sysRate < DAQ_16K_SAMPLE_SIZE; @@ -938,11 +621,7 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type memcpy(excnum, (const void *)(gdsPtr->tp[_2k_sys_offs][0]), sizeof(excnum)); memcpy(tpnum, (const void *)(gdsPtr->tp[2 + _2k_sys_offs][0]), sizeof(tpnum)); - //printf("TPnum[0]=%d\n", tpNum[0]); - //printf("excnum[0]=%d\n", excnum[0]); - //printf("tpnum[0]=%d\n", tpnum[0]); - - // Search and clear deselected test points + /// - ------ Search and clear deselected test points for (i = 0; i < DAQ_GDS_MAX_TP_ALLOWED; i++) { if (tpNum[i] == 0) continue; if (!in_the_lists(tpNum[i], i)) { @@ -1005,10 +684,6 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type localTable[ltSlot].decFactor = 1; dataInfo.tp[ltSlot].dataType = DAQ_DATATYPE_FLOAT; - // Need to recalculate offsets later - //offsetAccum += sysRate * 4; - //localTable[totalChans+1].offset = offsetAccum; - //if (slot < 24) gdsMonitor[slot] = tpn; gdsPtr->tp[2 + _2k_sys_offs][1][slot] = 0; tpNum[slot] = tpn; @@ -1047,8 +722,6 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type localTable[ltSlot].type = DAQ_SRC_NFM_EXC; localTable[ltSlot].fmNum = jj; localTable[ltSlot].sigNum = slot; - //offsetAccum += sysRate * 4; - //localTable[totalChans+1].offset = offsetAccum; localTable[ltSlot].decFactor = 1; excTable[slot].sigNum = tpn; excTable[slot].sysNum = localTable[ltSlot].sysNum; @@ -1061,10 +734,9 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type } } - // Calculate total number of test points to transmit + /// - ------ Calculate total number of test points to transmit totalChans = dataInfo.numChans; // Set to the DAQ channels number validTp = 0; - // totalSize = mnDaqSize; num_tps = 0; // Skip empty slots at the end @@ -1077,18 +749,15 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type totalChans += num_tps; validTp = num_tps; - curDaqBlockSize = crcLength * DAQ_NUM_DATA_BLOCKS_PER_SECOND; - - // Calculate the total transmission size - totalSize = crcLength + validTp * sysRate * 4; + /// - ------ Calculate the total transmission size (DAQ +TP) + xferInfo.totalSize = xferInfo.crcLength + validTp * sysRate * 4; - //printf("totalSize=%d; totalChans=%d; validTp=%d\n", totalSize, totalChans, validTp); // Assign offsets into the localTable - offsetAccum = tpStart; + xferInfo.offsetAccum = tpStart; for (i = 0; i < validTp; i++) { - localTable[dataInfo.numChans + i].offset = offsetAccum; - offsetAccum += sysRate * 4; + localTable[dataInfo.numChans + i].offset = xferInfo.offsetAccum; + xferInfo.offsetAccum += sysRate * 4; if (i < 32) gdsMonitor[i] = tpNum[i]; } @@ -1102,14 +771,239 @@ if(dataInfo.tp[ii].dataType == DAQ_DATATYPE_32BIT_INT) printf("Found int32 type for(ii=0;ii<validTp;ii++) tpNumNet[ii] = tpNum[ii]; validTpNet = validTp; - totalSizeNet = totalSize; + xferInfo.totalSizeNet = xferInfo.totalSize; } } /* End done 16Hz Cycle */ } /* End case write */ - /* Return the FE total DAQ data rate */ - return((totalSize*DAQ_NUM_DATA_BLOCKS_PER_SECOND)/1000); + /// \> Return the FE total DAQ data rate */ + return((xferInfo.totalSize*DAQ_NUM_DATA_BLOCKS_PER_SECOND)/1000); + +} + +// ************************************************************************************** +/// @author R.Bork\n +/// @brief This function updates the DAQ configuration from information +///< loaded from EPICS by the RCG EPICS sequencer.\n +/// @param[out] dataInfo Pointer to DAQ local configuration table +/// @param[in] pInfo Pointer to DAQ config info in shared memory +/// @param[in] pEpics Pointer to beginning of EPICS data. +/// @return Size, in bytes, of DAQ data. +// ************************************************************************************** +int daqConfig( DAQ_INFO_BLOCK *dataInfo, + DAQ_INFO_BLOCK *pInfo, + char *pEpics + ) +{ +int ii,jj; // Loop counters +int epicsIntXferSize = 0; // Size, in bytes, of EPICS integer type data. +int dataLength = 0; // Total size, in bytes, of data to be sent +int status = 0; + +/// \> Verify correct channel count before proceeding. \n +/// - ---- Required to be at least one and not more than DCU_MAX_CHANNELS. + status = pInfo->numChans; + if((status < 1) || (status > DCU_MAX_CHANNELS)) + { + printf("Invalid num daq chans = %d\n",status); + return(-1); + } + + /// \> Get the number of fast channels to be acquired + dataInfo->numChans = pInfo->numChans; + +/// \> Setup EPICS channel information/pointers + dataInfo->numEpicsInts = pInfo->numEpicsInts; + dataInfo->numEpicsFloats = pInfo->numEpicsFloats; + dataInfo->numEpicsFilts = pInfo->numEpicsFilts; + dataInfo->numEpicsTotal = pInfo->numEpicsTotal; + pEpicsIntData = pEpics; + epicsIntXferSize = dataInfo->numEpicsInts * 4; + + dataInfo->epicsdblDataOffset = 0; + dataInfo->cpyepics2times = 0; + dataInfo->cpyIntSize[0] = dataInfo->numEpicsInts * 4; + dataInfo->cpyIntSize[1] = 0; + + ii = (sizeof(CDS_EPICS_OUT) / 4); + jj = dataInfo->numEpicsInts - ii; + printf("Have %d CDS epics integer and %d USR epics integer channels\n",ii,jj); + ii *= 4; + jj *= 4; + + /// \> Look for memory holes ie integer types not ending on 8 byte boundary. + /// Need to check both standard CDS struct and User channels + /// - ---- If either doesn't end on 8 byte boundary, then a 4 byte hole will appear + /// before the double type data in shared memory. + if((ii % 8) || (jj % 8)) { + printf("Have at least 1 int mem hole %d %d \n",ii,jj); + dataInfo->epicsdblDataOffset = 4; + } + if ((ii%8) &&(jj>0)) { + /// - ---- If standard CDS struct doesn't end on 8 byte boundary, then + /// have 4 byte mem hole after CDS data + /// This will require 2 memcpys of integer data to get 8 byte alignment for xfer to DAQ buffer.. + dataInfo->cpyIntSize[0] = ii; + dataInfo->cpyIntSize[1] = jj; + dataInfo->cpyepics2times = 1; + dataInfo->epicsdblDataOffset += 4; + printf("Have 2 mem holes %d %d \nNeet to cpy ints twice - size 1 = %d size 2 = %d \n",ii,jj,dataInfo->cpyIntSize[0],dataInfo->cpyIntSize[1]); + } + + /// \> Set the pointer to start of EPICS double type data in shared memory. \n + /// - ---- Ptr to double type data is at EPICS integer start + EPICS integer size + Memory holes + pEpicsDblData = (pEpicsIntData + epicsIntXferSize + dataInfo->epicsdblDataOffset); + + // Send EPICS data diags to dmesg + printf("DAQ EPICS INT DATA is at 0x%x with size %d\n",(long)pEpicsIntData,epicsIntXferSize); + printf("DAQ EPICS FLT DATA is at 0x%x\n",(long)pEpicsDblData); + printf("DAQ EPICS: Int = %d Flt = %d Filters = %d Total = %d Fast = %d\n",dataInfo->numEpicsInts,dataInfo->numEpicsFloats,dataInfo->numEpicsFilts, dataInfo->numEpicsTotal, dataInfo->numChans); + /// \> Initialize CRC length with EPICS data size. + dataLength = 4 * dataInfo->numEpicsTotal; + printf("crc length epics = %d\n",dataLength); + + /// \> Get the DAQ configuration information for all fast DAQ channels and calc a crc checksum length + for(ii=0;ii<dataInfo->numChans;ii++) + { + dataInfo->tp[ii].tpnum = pInfo->tp[ii].tpnum; + dataInfo->tp[ii].dataType = pInfo->tp[ii].dataType; + dataInfo->tp[ii].dataRate = pInfo->tp[ii].dataRate; + if(dataInfo->tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) + dataLength += 2 * dataInfo->tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS; + else + dataLength += 4 * dataInfo->tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS; + } + /// \> Set DAQ bytes/sec global, which is output to EPICS by controller.c + curDaqBlockSize = dataLength * DAQ_NUM_DATA_BLOCKS_PER_SECOND; + + /// \> RETURN dataLength, used in other code for CRC checksum byte count + return(dataLength); + +} + +// ************************************************************************************** +/// @author R.Bork\n +/// @brief This function populates the local DAQ/TP tables. +/// @param *pDxi Pointer to struct with data transfer size information. +/// @param localTable[] Table to be populated with data pointer information +/// @param sysRate Number of code cycles in 1/16 second. +/// @param *dataInfo DAQ configuration information +/// @param *daqRange Info on GDS TP number ranges which provides type information +/// @return 0=OK or -1=FAIL +// ************************************************************************************** +int loadLocalTable(DAQ_XFER_INFO *pDxi, + DAQ_LKUP_TABLE localTable[], + int sysRate, + DAQ_INFO_BLOCK *dataInfo, + DAQ_RANGE *daqRange + ) +{ +int ii,jj; + + + /// \> Get the .INI file crc checksum to pass to DAQ Framebuilders for config checking */ + pDxi->fileCrc = pInfo->configFileCRC; + /// \> Calculate the number of bytes to xfer on each call, based on total number + /// of bytes to write each 1/16sec and the front end data rate (2048/16384Hz) + pDxi->xferSize1 = pDxi->crcLength/sysRate; + pDxi->totalSize = pDxi->crcLength; + pDxi->totalSizeNet = pDxi->crcLength; + + printf (" xfer sizes = %d %d %d %d \n",sysRate,pDxi->xferSize1,pDxi->totalSize,pDxi->crcLength); + + if (pDxi->xferSize1 == 0) { + printf("DAQ size too small\n"); + return -1; + } + + /// \> Maintain 8 byte data boundaries for writing data, particularly important + /// when DMA xfers are used on 5565 RFM modules. Note that this usually results + /// in data not being written on every 2048/16384 cycle and last data xfer + /// in a 1/16 sec block well may be shorter than the rest. + pDxi->xferSize1 = ((pDxi->xferSize1/8) + 1) * 8; + printf("DAQ resized %d\n", pDxi->xferSize1); + + /// \> Find first memory location for fast data in read/write swing buffers. + pDxi->offsetAccum = 4 * dataInfo->numEpicsTotal; + localTable[0].offset = pDxi->offsetAccum; + + /// \> Fill in the local lookup table for finding data. + /// - (Need to develop a table of offset pointers to load data into swing buffers) \n + /// - (This is based on decimation factors and data size.) +for(ii=0;ii<dataInfo->numChans;ii++) + { + if ((dataInfo->tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS) > sysRate) { + /* Channel data rate is greater than system rate */ + printf("Channels %d has bad data rate %d\n", ii, dataInfo->tp[ii].dataRate); + return(-1); + } else { + /// - ---- Load decimation factor + localTable[ii].decFactor = sysRate/(dataInfo->tp[ii].dataRate / DAQ_NUM_DATA_BLOCKS); + } + + /// - ---- Calc offset into swing buffer for writing data + if(dataInfo->tp[ii].dataType == DAQ_DATATYPE_16BIT_INT) + pDxi->offsetAccum += (sysRate/localTable[ii].decFactor * 2); + else + pDxi->offsetAccum += (sysRate/localTable[ii].decFactor * 4); + + localTable[ii+1].offset = pDxi->offsetAccum; + /// - ---- Need to determine if data is from a filter module TP or non-FM TP and tag accordingly + if((dataInfo->tp[ii].tpnum >= daqRange->filtTpMin) && + (dataInfo->tp[ii].tpnum < daqRange->filtTpMax)) + /* This is a filter module testpoint */ + { + jj = dataInfo->tp[ii].tpnum - daqRange->filtTpMin; + /* Mark as coming from a filter module testpoint */ + localTable[ii].type = DAQ_SRC_FM_TP; + /* Mark which system filter module is in */ + localTable[ii].sysNum = jj / daqRange->filtTpSize; + jj -= localTable[ii].sysNum * daqRange->filtTpSize; + /* Mark which filter module within a system */ + localTable[ii].fmNum = jj / DAQ_NUM_FM_TP; + /* Mark which of three testpoints to store */ + localTable[ii].sigNum = jj % DAQ_NUM_FM_TP; + } + else if((dataInfo->tp[ii].tpnum >= daqRange->filtExMin) && + (dataInfo->tp[ii].tpnum < daqRange->filtExMax)) + /* This is a filter module excitation input */ + { + /* Mark as coming from a filter module excitation input */ + localTable[ii].type = DAQ_SRC_FM_EXC; + /* Mark filter module number */ + localTable[ii].fmNum = dataInfo->tp[ii].tpnum - daqRange->filtExMin; + } + else if((dataInfo->tp[ii].tpnum >= daqRange->xTpMin) && + (dataInfo->tp[ii].tpnum < daqRange->xTpMax)) + /* This testpoint is not part of a filter module */ + { + jj = dataInfo->tp[ii].tpnum - daqRange->xTpMin; + /* Mark as a non filter module testpoint */ + localTable[ii].type = DAQ_SRC_NFM_TP; + /* Mark the offset into the local data buffer */ + localTable[ii].sigNum = jj; + } + // :TODO: this is broken, needs some work to make extra EXC work. + else if((dataInfo->tp[ii].tpnum >= daqRange->xExMin) && + (dataInfo->tp[ii].tpnum < daqRange->xExMax)) + /* This exc testpoint is not part of a filter module */ + { + jj = dataInfo->tp[ii].tpnum - daqRange->xExMin; + /* Mark as a non filter module testpoint */ + localTable[ii].type = DAQ_SRC_NFM_EXC; + /* Mark the offset into the local data buffer */ + localTable[ii].fmNum = jj; + localTable[ii].sigNum = jj; + } + else + { + printf("Invalid chan num found %d = %d\n",ii,dataInfo->tp[ii].tpnum); + return(-1); + } +} +return(0); +/// \> RETURN 0=OK or -1=FAIL }