void *_laytube_toFile(void *args){ long unsigned int expansion_size; void *pause_after; tubeID *pTube; rohrStation sendingStation; rohrStation receivingStation; pTube = (tubeID *) args; /* Populate Station Information */ sendingStation.stationSize = comedi_get_buffer_size(pTube->dev, pTube->subdev); receivingStation.stationSize = _file_size(pTube->tail); expansion_size = 64 * sysconf(_SC_PAGESIZE); /* Set file expansion size to a mulitple of memory page size */ if (expansion_size < sendingStation.stationSize){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } /* Check for empty file */ if (receivingStation.stationSize < 1){ receivingStation.stationSize = expansion_size; /* Let's make the file one page-size in length */ ftruncate(pTube->tail, receivingStation.stationSize); } /* Set up COMEDI ring buffer memory map */ sendingStation.firstByte = mmap(NULL, sendingStation.stationSize, PROT_READ, MAP_SHARED, pTube->mouth, 0); if (sendingStation.firstByte == MAP_FAILED){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } sendingStation.address = sendingStation.firstByte; sendingStation.lastByte = sendingStation.firstByte + sendingStation.stationSize - 1; /* Last valid byte */ /* Set up HDD file memory map */ receivingStation.firstByte = mmap(NULL, receivingStation.stationSize, PROT_WRITE | MAP_HUGETLB, MAP_SHARED, pTube->tail, 0); if (receivingStation.firstByte == MAP_FAILED){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } receivingStation.address = receivingStation.firstByte; receivingStation.lastByte = receivingStation.firstByte + receivingStation.stationSize - 1; /* Last valid byte */ /* Stations are setup... set status and command flags... */ pTube->tubeCmd = 0x00; pTube->tubeStatus = TUBE_INPLACE; /* <-- un-blocks laytube_toFile to return to calling function */ /* Core algorithm - This while loop handles the data transfer from ring buffer to disk */ while( !(pTube->tubeCmd & TUBE_STOP) ){ /* Check if the storage file is out or about to be out of space */ if (sendingStation.stationSize >= (receivingStation.lastByte - receivingStation.address) ){ if (_growStation(&receivingStation, pTube->tail, expansion_size) == -1){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } } pause_after = sendingStation.firstByte + comedi_get_buffer_contents(pTube->dev, pTube->subdev) - 1; if (pause_after < sendingStation.address){ pTube->bytesMoved = receivingStation.address - receivingStation.firstByte; /* comedi_poll(pTube->dev, pTube->subdev)); */ usleep(10); /* TODO: optimize by setting sleep number to best guess at when data might show up again */ } else if (pause_after < sendingStation.lastByte) /* Confirm COMEDI ring buffer has not aliased */ { do { *((CARRIER *)receivingStation.address++) = *((CARRIER *)sendingStation.address++); } while(sendingStation.address <= pause_after); } else if (pause_after >= sendingStation.lastByte) /* COMEDI ring buffer has aliased... copy up to end of ring buffer and reset */ { do { *((CARRIER *)receivingStation.address++) = *((CARRIER *)sendingStation.address++); } while(sendingStation.address <= sendingStation.lastByte); comedi_mark_buffer_read(pTube->dev, pTube->subdev, sendingStation.stationSize); /* Reset the ring buffer mark */ sendingStation.address = sendingStation.firstByte; } else { pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(0); } } /* Clean up Stations, truncate file, flush tube */ expansion_size = receivingStation.address - receivingStation.firstByte; /* 'address' should point to one byte past last byte written */ ftruncate(pTube->tail, expansion_size); fsync(pTube->tail); pTube->bytesMoved = expansion_size; pTube->tubeStatus = pTube->tubeStatus | TUBE_EXIT; pthread_exit(0); }
int myBoard_distributeData( int board ) { MY_BOARD_HARDWARE *pBoardHard = myBoard_getHardwareBoard( board ); MY_BOARD_SOFTWARE *pBoardSoft = myBoard_getSoftwareBoard( board ); if (pBoardHard == NULL || pBoardSoft == NULL) { return 0; } int numAvailableByte = comedi_get_buffer_contents( pBoardHard->p_comediFileHandle, pBoardHard->subDeviceNumber ); if (numAvailableByte >= pBoardHard->buffer_size_in_byte) { fprintf( stderr, "processing too slow, lost data for board[%d]\n", board ); } size_t dataSize = (pBoardHard->valueIsLsampl_t)?sizeof(lsampl_t):sizeof(sampl_t); int numAvailableSample = numAvailableByte / dataSize; int numInput = pBoardSoft->numberOfActiveAnalogInputs; /* we only deal with whole scans */ int numScan = numAvailableSample / numInput; int odd = numAvailableSample % numInput; /* fprintf( stderr, "checking data: numAvailableSample=%d, numScan=%d odd=%d\n", numAvailableSample, numScan, odd ); */ if (numScan <= 0) { return 0; } numAvailableSample = numInput * numScan; int i; epicsMutexMustLock( pBoardSoft->boardLock ); if (pBoardHard->valueIsLsampl_t) { lsampl_t *pBuffer = (lsampl_t*)pBoardHard->buffer; for (i = 0; i < numAvailableSample; ++i) { int offset = pBoardHard->indexRead++ % pBoardHard->buffer_size_in_sample; double vRaw = pBuffer[offset]; int indexChannel = i % numInput; double v = vRaw * pBoardHard->channelRawToVoltA[indexChannel] + pBoardHard->channelRawToVoltB[indexChannel]; appendDataToMyRingBuffer( pBoardSoft->channel_buffer + indexChannel, v, 0 ); } } else { sampl_t *pBuffer = (sampl_t*)pBoardHard->buffer; for (i = 0; i < numAvailableSample; ++i) { int offset = pBoardHard->indexRead++ % pBoardHard->buffer_size_in_sample; double vRaw = pBuffer[offset]; int indexChannel = i % numInput; double v = vRaw * pBoardHard->channelRawToVoltA[indexChannel] + pBoardHard->channelRawToVoltB[indexChannel]; appendDataToMyRingBuffer( pBoardSoft->channel_buffer + indexChannel, v, 0 ); } } epicsMutexUnlock( pBoardSoft->boardLock ); int numReadByte = numAvailableSample * dataSize; comedi_mark_buffer_read( pBoardHard->p_comediFileHandle, pBoardHard->subDeviceNumber, numReadByte ); scanIoRequest( pBoardSoft->ioScanPvt ); return numScan; }