/************************************************************************** * * Copyright (c) 2026-2026 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file BarcodeReader.c * * @author (last) Vijay Pamula * @date (last) 19-August-2026 * * @author (original) Vijay Pamula * @date (original) 19-August-2026 * ***************************************************************************/ #include "BarcodeReader.h" #include "Common.h" #include "FpgaTD.h" #include "Timers.h" /** * @addtogroup BarcodeReader * @{ */ // ********** private definitions ********** #define BARCODE_SCAN_TIMEOUT_MS 5000 ///< Maximum time allowed for a barcode scan to complete. #define BARCODE_EXPECTED_DATA_LENGTH 36 ///< Expected blood tubing set barcode data length. #define BARCODE_MAX_DATA_LENGTH 128 ///< Maximum number of barcode data bytes that can be stored. #define BARCODE_COMMAND_READY_MASK 0x01 ///< Bit mask indicating the barcode interface is ready. #define BARCODE_FIFO_READ_COUNT_MASK 0x0F80 ///< Bit mask for barcode response FIFO read word count. #define BARCODE_FIFO_READ_COUNT_SHIFT 7 ///< Bit shift for barcode response FIFO read word count. #define BARCODE_RESPONSE_START_CHAR '#' ///< Barcode response start character. #define BARCODE_RESPONSE_END_CHAR '\r' ///< Barcode response termination character. #define BARCODE_FIFO_READ_BYTE_COUNT 4 ///< Number of barcode response bytes read from the FPGA FIFO per read. /// Barcode reader state machine. typedef enum barcodeReaderStates { BARCODE_READER_IDLE_STATE = 0, ///< Waits for a barcode scan request. BARCODE_READER_TRIGGER_STATE, ///< Triggers a barcode scan through the FPGA interface. BARCODE_READER_WAIT_RESPONSE_STATE, ///< Waits for barcode response data or timeout/error condition. BARCODE_READER_READ_FIFO_STATE ///< Reads barcode response data from the FPGA FIFO. } BARCODE_READER_STATE_T; // ********** private data ********** static BARCODE_READER_STATE_T barcodeReaderState; static BARCODE_SCAN_STATUS_T barcodeScanStatus; static BOOL pendingBarcodeScanRequest; static U08 barcodeData[ BARCODE_MAX_DATA_LENGTH ]; static U16 barcodeDataLength; static U32 barcodeScanStartTime; static U16 barcodeUartErrorStartCount; static BOOL barcodeFifoReadPending; static BOOL barcodeResponseComplete; // ********** private function prototypes ********** static BARCODE_READER_STATE_T handleBarcodeReaderIdleState( void ); static BARCODE_READER_STATE_T handleBarcodeReaderTriggerState( void ); static BARCODE_READER_STATE_T handleBarcodeReaderWaitResponseState( void ); static BARCODE_READER_STATE_T handleBarcodeReaderReadFifoState( void ); static BOOL isBarcodeResponseValid( void ); /*********************************************************************//** * @brief * The initBarcodeReaderDriver function initializes the barcode reader * driver state and scan data. * @details \b Inputs: none. * @details \b Outputs: barcodeReaderState, barcodeScanStatus, * pendingBarcodeScanRequest, barcodeData[], barcodeDataLength, * barcodeScanStartTime, barcodeUartErrorStartCount, * barcodeFifoReadPending, barcodeResponseComplete * @return none *************************************************************************/ void initBarcodeReaderDriver( void ) { U16 index; barcodeReaderState = BARCODE_READER_IDLE_STATE; barcodeScanStatus = BARCODE_SCAN_STATUS_IDLE; pendingBarcodeScanRequest = FALSE; barcodeDataLength = 0; barcodeScanStartTime = 0; barcodeUartErrorStartCount = 0; barcodeFifoReadPending = FALSE; barcodeResponseComplete = FALSE; for ( index = 0; index < BARCODE_MAX_DATA_LENGTH; index++ ) { barcodeData[index] = 0; } } /*********************************************************************//** * @brief * The execBarcodeReaderDriver function executes the barcode reader * state machine. * @details \b Inputs: barcodeReaderState. * @details \b Outputs: barcodeReaderState. * @return none *************************************************************************/ void execBarcodeReaderDriver( void ) { switch ( barcodeReaderState ) { case BARCODE_READER_IDLE_STATE: barcodeReaderState = handleBarcodeReaderIdleState(); break; case BARCODE_READER_TRIGGER_STATE: barcodeReaderState = handleBarcodeReaderTriggerState(); break; case BARCODE_READER_WAIT_RESPONSE_STATE: barcodeReaderState = handleBarcodeReaderWaitResponseState(); break; case BARCODE_READER_READ_FIFO_STATE: barcodeReaderState = handleBarcodeReaderReadFifoState(); break; default: barcodeReaderState = BARCODE_READER_IDLE_STATE; barcodeScanStatus = BARCODE_SCAN_STATUS_ERROR; break; } } /*********************************************************************//** * @brief * The requestBarcodeScan function requests a new barcode scan. * @details \b Inputs: barcodeReaderState, pendingBarcodeScanRequest. * @details \b Outputs: pendingBarcodeScanRequest, barcodeScanStatus. * @return TRUE if the barcode scan request is accepted, FALSE otherwise. *************************************************************************/ BOOL requestBarcodeScan( void ) { BOOL result = FALSE; if ( ( BARCODE_READER_IDLE_STATE == barcodeReaderState ) && ( FALSE == pendingBarcodeScanRequest ) ) { pendingBarcodeScanRequest = TRUE; barcodeScanStatus = BARCODE_SCAN_STATUS_IN_PROGRESS; result = TRUE; } return result; } /*********************************************************************//** * @brief * The getBarcodeScanStatus function returns the current barcode scan * status. * @details \b Inputs: barcodeScanStatus. * @details \b Outputs: none. * @return Current barcode scan status. *************************************************************************/ BARCODE_SCAN_STATUS_T getBarcodeScanStatus( void ) { return barcodeScanStatus; } /*********************************************************************//** * @brief * The getBarcodeDataLength function returns the number of barcode data * bytes received. * @details \b Inputs: barcodeDataLength. * @details \b Outputs: none. * @return Number of valid barcode data bytes received. *************************************************************************/ U16 getBarcodeDataLength( void ) { return barcodeDataLength; } /*********************************************************************//** * @brief * The getBarcodeData function returns the received barcode data buffer. * @details \b Inputs: barcodeData[]. * @details \b Outputs: none. * @return Pointer to the received barcode data buffer. *************************************************************************/ const U08 *getBarcodeData( void ) { return barcodeData; } /*********************************************************************//** * @brief * The handleBarcodeReaderIdleState function handles the barcode reader * idle state. * @details \b Inputs: pendingBarcodeScanRequest. * @details \b Outputs: pendingBarcodeScanRequest, barcodeScanStatus, * barcodeDataLength, barcodeScanStartTime, barcodeUartErrorStartCount, * barcodeFifoReadPending, barcodeResponseComplete * @return Next barcode reader state. *************************************************************************/ static BARCODE_READER_STATE_T handleBarcodeReaderIdleState( void ) { BARCODE_READER_STATE_T nextState = BARCODE_READER_IDLE_STATE; if ( TRUE == pendingBarcodeScanRequest ) { pendingBarcodeScanRequest = FALSE; barcodeScanStatus = BARCODE_SCAN_STATUS_IN_PROGRESS; barcodeDataLength = 0; barcodeFifoReadPending = FALSE; barcodeResponseComplete = FALSE; barcodeUartErrorStartCount = getFPGABarcodeUartError(); barcodeScanStartTime = getMSTimerCount(); nextState = BARCODE_READER_TRIGGER_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBarcodeReaderTriggerState function waits for the barcode * interface to become ready and triggers a barcode scan. * @details \b Inputs: barcodeScanStartTime, FPGA barcode command status. * @details \b Outputs: barcodeScanStatus, FPGA barcode trigger control. * @return Next barcode reader state. *************************************************************************/ static BARCODE_READER_STATE_T handleBarcodeReaderTriggerState( void ) { BARCODE_READER_STATE_T nextState = BARCODE_READER_TRIGGER_STATE; if ( 0 != ( getFPGABarcodeCommandStatus() & BARCODE_COMMAND_READY_MASK ) ) { setFPGABarcodeTriggerControl( 1 ); nextState = BARCODE_READER_WAIT_RESPONSE_STATE; } else if ( TRUE == didTimeout( barcodeScanStartTime, BARCODE_SCAN_TIMEOUT_MS ) ) { barcodeScanStatus = BARCODE_SCAN_STATUS_TIMEOUT; nextState = BARCODE_READER_IDLE_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBarcodeReaderWaitResponseState function waits for barcode * response data from the FPGA. * @details \b Inputs: barcodeScanStartTime, barcodeUartErrorStartCount, * FPGA barcode UART error count, FPGA barcode FIFO status. * @details \b Outputs: barcodeScanStatus. * @return Next barcode reader state. *************************************************************************/ static BARCODE_READER_STATE_T handleBarcodeReaderWaitResponseState( void ) { BARCODE_READER_STATE_T nextState = BARCODE_READER_WAIT_RESPONSE_STATE; U16 fifoStatus = getFPGABarcodeFIFOStatus(); U16 fifoCount = ( fifoStatus & BARCODE_FIFO_READ_COUNT_MASK ) >> BARCODE_FIFO_READ_COUNT_SHIFT; if ( getFPGABarcodeUartError() != barcodeUartErrorStartCount ) { barcodeScanStatus = BARCODE_SCAN_STATUS_ERROR; nextState = BARCODE_READER_IDLE_STATE; } else if ( fifoCount > 0 ) { nextState = BARCODE_READER_READ_FIFO_STATE; } else if ( TRUE == didTimeout( barcodeScanStartTime, BARCODE_SCAN_TIMEOUT_MS ) ) { barcodeScanStatus = BARCODE_SCAN_STATUS_TIMEOUT; nextState = BARCODE_READER_IDLE_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBarcodeReaderReadFifoState function reads barcode response * data from the FPGA FIFO. * @details \b Inputs: barcodeFifoReadPending, barcodeResponseComplete, * barcodeDataLength, barcodeScanStartTime, barcodeUartErrorStartCount, * FPGA barcode UART error count, FPGA barcode FIFO status, * FPGA barcode FIFO data. * @details \b Outputs: barcodeFifoReadPending, barcodeResponseComplete, * barcodeData[], barcodeDataLength, barcodeScanStatus, * FPGA barcode FIFO control. * @return Next barcode reader state. *************************************************************************/ static BARCODE_READER_STATE_T handleBarcodeReaderReadFifoState( void ) { BARCODE_READER_STATE_T nextState = BARCODE_READER_READ_FIFO_STATE; U16 fifoStatus = getFPGABarcodeFIFOStatus(); U16 fifoCount = ( fifoStatus & BARCODE_FIFO_READ_COUNT_MASK ) >> BARCODE_FIFO_READ_COUNT_SHIFT; U32 barcodeFifoData; U08 barcodeByte; U08 index; if ( getFPGABarcodeUartError() != barcodeUartErrorStartCount ) { barcodeFifoReadPending = FALSE; barcodeScanStatus = BARCODE_SCAN_STATUS_ERROR; nextState = BARCODE_READER_IDLE_STATE; } else if ( TRUE == didTimeout( barcodeScanStartTime, BARCODE_SCAN_TIMEOUT_MS ) ) { barcodeFifoReadPending = FALSE; barcodeScanStatus = BARCODE_SCAN_STATUS_TIMEOUT; nextState = BARCODE_READER_IDLE_STATE; } else if ( TRUE == barcodeFifoReadPending ) { barcodeFifoReadPending = FALSE; barcodeFifoData = getFPGABarcodeFIFOData(); /* * Once the response end character has been received, continue * draining remaining FIFO words but do not store additional data. */ if ( FALSE == barcodeResponseComplete ) { for ( index = 0; index < BARCODE_FIFO_READ_BYTE_COUNT; index++ ) { barcodeByte = (U08)( ( barcodeFifoData >> ( ( BARCODE_FIFO_READ_BYTE_COUNT - 1 - index ) * 8 ) ) & 0xFF ); /* * Ignore any data until the barcode response start * character is received. */ if ( 0 == barcodeDataLength ) { if ( BARCODE_RESPONSE_START_CHAR != barcodeByte ) { continue; } } if ( barcodeDataLength < BARCODE_MAX_DATA_LENGTH ) { barcodeData[barcodeDataLength] = barcodeByte; barcodeDataLength++; if ( BARCODE_RESPONSE_END_CHAR == barcodeByte ) { barcodeResponseComplete = TRUE; break; } } else { barcodeScanStatus = BARCODE_SCAN_STATUS_ERROR; nextState = BARCODE_READER_IDLE_STATE; break; } } } } else if ( fifoCount > 0 ) { setFPGABarcodeFIFOControl( 1 ); barcodeFifoReadPending = TRUE; } else if ( TRUE == barcodeResponseComplete ) { if ( TRUE == isBarcodeResponseValid() ) { barcodeScanStatus = BARCODE_SCAN_STATUS_SUCCESS; } else { barcodeScanStatus = BARCODE_SCAN_STATUS_ERROR; } nextState = BARCODE_READER_IDLE_STATE; } else { nextState = BARCODE_READER_WAIT_RESPONSE_STATE; } return nextState; } /*********************************************************************//** * @brief * The isBarcodeResponseValid function validates the barcode response * framing. * @details \b Inputs: barcodeData[], barcodeDataLength. * @details \b Outputs: none. * @return TRUE if the barcode response framing is valid, otherwise FALSE. *************************************************************************/ static BOOL isBarcodeResponseValid( void ) { BOOL valid = FALSE; if ( barcodeDataLength > 2 ) { if ( ( BARCODE_RESPONSE_START_CHAR == barcodeData[0] ) && ( BARCODE_RESPONSE_END_CHAR == barcodeData[barcodeDataLength - 1] ) ) { valid = TRUE; } } return valid; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testBarcodeScanRequest function requests a barcode scan for * Dial-in testing. * @details \b Inputs: barcodeReaderState, pendingBarcodeScanRequest * @details \b Outputs: pendingBarcodeScanRequest, barcodeScanStatus * @param message Dial-in barcode scan test request. * @return TRUE if the barcode scan request is accepted, otherwise FALSE. *************************************************************************/ BOOL testBarcodeScanRequest( MESSAGE_T *message ) { BOOL result = FALSE; (void)message; result = requestBarcodeScan(); return result; } /**@}*/