/************************************************************************** * * Copyright (c) 2025-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 ConductivityTeensy.c * * @author (last) Arpita Srivastava * @date (last) 3-Nov-2025 * * @author (original) Arpita Srivastava * @date (original) 3-Nov-2025 * ***************************************************************************/ #include // Used for calculating the polynomial calibration equation. #include // For memcpy #include "sci.h" #include "sys_dma.h" #include "Comm.h" #include "ConductivityTeensy.h" #include "Timers.h" // ********** private definitions ********** #define SCI_RECEIVE_DMA_REQUEST 30 ///< Serial port receive DMA request line. #define SCI_TRANSMIT_DMA_REQUEST 31 ///< Serial port transmit DMA request line. #define COND_CMD_Q_LEN 8 ///< Maximum number of cmds that can be queue'd. #define QUEUE_START_INDEX 0U ///< Queue start index. #define COND_WRITE_CMD_BUFFER_LEN 256 ///< Conductivity DMA transmit buffer length in bytes. #define COND_WRITE_RSP_BUFFER_LEN 256 ///< Conductivity DMA receive buffer length in bytes. #define COND_TX_BUFFER_LEN 256 ///< Conductivity transmit buffer length in bytes. #define COND_RX_BUFFER_LEN 256 ///< Conductivity receive buffer length in bytes. #define RX_SIZE_INIT_SENSOR 2 ///< Expected response bytes length of init sensor cmd. #define RX_SIZE_GET_INIT_STATUS 1 ///< Expected response bytes length of get init status cmd. #define RX_SIZE_UPDATE_EEPROM 1 ///< Expected response bytes length of update eeprom cmd. #define RX_SIZE_GET_EEPROM ( sizeof( COND_EEPROM_DATA_T ) ) ///< Expected response bytes length of get eeprom data cmd. #define RX_SIZE_UPDATE_MEASUREMENT_SETTINGS 1 ///< Expected response bytes length of update measurement settings cmd. #define RX_SIZE_GET_MEASUREMENT_SETTNGS ( sizeof( COND_MEASUREMENT_SETTINGS_T ) ) ///< Expected response bytes length of get measurement settings cmd. #define RX_SIZE_START_MEASUREMENT ( sizeof( COND_SENSOR_DATA_T ) ) ///< Expected response bytes length of start measurement cmd. #define RX_SIZE_STOP_MEASUREMENT 0 ///< Expected response bytes length of stop measurement cmd. #define RX_SIZE_GET_ALL_MEASUREMENTS ( 6 * RX_SIZE_START_MEASUREMENT ) ///< Expected response bytes length of get all sensor measurements cmd #define RX_SIZE_SELECT_SENSOR 0 ///< Expected response bytes length of select sensor cmd. #define RX_SIZE_GET_SINGLE_MEASUREMENT ( sizeof( COND_SENSOR_DATA_T ) ) ///< Expected response bytes length of get single sensor measurement cmd. #define COND_STATUS_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Timeout before which we should receive acknowledgment from teensy #define COND_DATA_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Timeout before which we should receive data from teensy // ********** private data ********** static COND_COMM_STATE_T condCommState; static U32 condResponseTime; ///< Tracks duration between cmd sent and its response received. static U32 condReceiptCounter; ///< Conductivity response receipt counter. static U32 condTransmitCounter; ///< Conductivity command transmit counter. static BOOL condAutomatedDataPolling; ///< Flag indicating automated conductivity measurements polling has started. static BOOL condWriteCommandInProgress; ///< Flag indicating an Conductivity write command is in progress. static BOOL condReadCommandInProgress; ///< Flag indicating an Conductivity read command is in progress. static BOOL condBulkWriteAndReadInProgress; ///< Flag indicating an Conductivity bulk write and read command are in progress. static BOOL condWriteCmdRspnsRcvd; ///< Flag indicating a response to an Conductivity write command has been received. // Conductivity comm buffers static U08 condWriteCmdBuffer[ COND_WRITE_CMD_BUFFER_LEN ]; ///< Conductivity write command buffer. Holds the next Conductivity write command to be transmitted. static U08 condWriteResponseBuffer[ COND_WRITE_RSP_BUFFER_LEN ]; ///< Conductivity write command response buffer. Memory reserved to capture the response to the last Conductivity write command. static U08 condTxBuffer[ COND_TX_BUFFER_LEN ]; ///< Conductivity transmit buffer. static U08 condRxBuffer[ COND_RX_BUFFER_LEN ]; ///< Conductivity receive buffer // Conductivity queue buffer and supporting variables. static TEENSY_CMD_INDEX_T condCmdQ[ COND_CMD_Q_LEN ]; ///< Conductivity command queue buffer. static U08 queueCount; ///< Queue count. static U08 queueRearIndex; ///< Queue rear index. static U08 queueFrontIndex; ///< Queue front index. static TEENSY_CMD_INDEX_T currentCmd; ///< Current command being executed in the state machine // Conductivity DMA control records static g_dmaCTRL condDMAWriteControlRecord; ///< DMA record for controlling a DMA write command transmission from buffer. static g_dmaCTRL condDMAWriteRespControlRecord; ///< DMA record for controlling a DMA write command reception to buffer. // Conductivity cmd data structs static COND_INIT_STATUS_T condInitStatus; ///< Received teensy and all sensors initialization status. static COND_UPDATE_EEPROM_STATUS_T condUpdateEEPROMstatus; ///< Received update EEPROM status. static COND_UPDATE_MST_STATUS_T condUpdateSettingStatus[ MAX_COND_MST_PARAM_IDX ]; ///< Received update measurement settings status. static U08 condStopMeasurementSatus; ///< Received acknowledgment of stop measurement command static COND_SENSOR_DATA_T condRawMeasurement[ MAX_TEENSY_SENSOR ]; ///< Received raw sensor values (includes impedance and rtd). static COND_CALCULATED_MEASUREMENTS_T condCalculatedMeasurement[ MAX_TEENSY_SENSOR ]; ///< Calculated conductivity and temperature values static COND_COEFF_T condCoeff[ MAX_TEENSY_SENSOR ]; ///< Coefficients used to calculate conductivity and temperature values. static TEENSY_SENSOR_INDEX_T currentSelectedSensor; ///< Current selected sensor to get measurement of single sensor. Value 1 to 6. static COND_EEPROM_DATA_T eePromDataTX; ///< Transmitted EEPROM data to Teensy for update EEPROM cmd. static COND_EEPROM_DATA_T eePromDataRX; ///< Received EEPROM data by get EEPROM data cmd. static COND_MEASUREMENT_SETTINGS_T measurementSettingsTX; ///< Transmitted measurement settings to Teensy for update measurement settings cmd. static COND_MEASUREMENT_SETTINGS_T measurementSettingsRX; ///< Received measurement settings by get measurement settings cmd. // Command Map static const COND_CMD_DATA_T teensyCmdMap[] = { // Command Index / Sub state Command Length of expected response data { TEENSY_CMD_INIT_SENSOR , ( U08* )"a" , RX_SIZE_INIT_SENSOR }, { TEENSY_CMD_GET_INIT_STATUS , ( U08* )"l" , RX_SIZE_GET_INIT_STATUS }, { TEENSY_CMD_UPDATE_EEPROM_DATA , ( U08* )"upe" , RX_SIZE_UPDATE_EEPROM }, { TEENSY_CMD_GET_EEPROM_DATA , ( U08* )"e" , RX_SIZE_GET_EEPROM }, { TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS , ( U08* )"mst" , RX_SIZE_UPDATE_MEASUREMENT_SETTINGS }, { TEENSY_CMD_GET_MEASUREMENT_SETTINGS , ( U08* )"k" , RX_SIZE_GET_MEASUREMENT_SETTNGS }, { TEENSY_CMD_START_MEASUREMENT , ( U08* )"m" , RX_SIZE_START_MEASUREMENT }, { TEENSY_CMD_STOP_MEASUREMENT , ( U08* )"n" , RX_SIZE_STOP_MEASUREMENT }, { TEENSY_CMD_GET_ALL_MEASUREMENTS , ( U08* )"g" , RX_SIZE_GET_ALL_MEASUREMENTS }, { TEENSY_CMD_GET_SINGLE_MEASUREMENT , ( U08* )"h" , RX_SIZE_GET_SINGLE_MEASUREMENT }, }; // ********** private function prototypes ********** static void initCondDMAchannels( void ); static void initEEPROMdata( void ); static void initMeasurementSettings( void ); static COND_COMM_STATE_T handleConductivityIdle( void ); static COND_COMM_STATE_T handleConductivityTX( void ); static COND_COMM_STATE_T handleConductivityRX( void ); static COND_COMM_STATE_T handleFailedState( void ); static void consumeUnexpectedConductivityData( void ); static void setupConductivityDMAForWriteCmd( U32 bytes2Transmit ); static void startConductivityDMAWriteCmd( void ); static void setupConductivityDMAForWriteResp( U32 bytes2Receive ); static void startConductivityDMAReceiptOfWriteResp( void ); static BOOL isQueueFull ( void ); static BOOL isQueueEmpty ( void ); static BOOL enqueue ( TEENSY_CMD_INDEX_T cmd ); static void dequeue( void ); static BOOL txTeensyWriteCmd( TEENSY_CMD_INDEX_T cmdIndex, const U08* param ); static BOOL rxTeensyReadRsp( TEENSY_CMD_INDEX_T cmdIndex ); static COND_COMM_STATE_T txInitSensor( void ); static COND_COMM_STATE_T rxInitSensor( void ); static COND_COMM_STATE_T txGetInitStatus( void ); static COND_COMM_STATE_T rxGetInitStatus( void ); static COND_COMM_STATE_T txUpdateEEPROMdata( void ); static COND_COMM_STATE_T rxUpdateEEPROMdata( void ); static COND_COMM_STATE_T txGetEEPROMdata( void ); static COND_COMM_STATE_T rxGetEEPROMdata( void ); static COND_COMM_STATE_T txUpdateMeasurementSettings( void ); static COND_COMM_STATE_T rxUpdateMeasurementSettings( void ); static COND_COMM_STATE_T txGetMeasurementSettings( void ); static COND_COMM_STATE_T rxGetMeasurementSettings( void ); static COND_COMM_STATE_T txStartMeasurements( void ); static COND_COMM_STATE_T rxStartMeasurements( void ); static COND_COMM_STATE_T txStopMeasurement( void ); static COND_COMM_STATE_T rxStopMeasurement( void ); static COND_COMM_STATE_T txGetAllMeasurements( void ); static COND_COMM_STATE_T rxGetAllMeasurements( void ); static COND_COMM_STATE_T txGetSingleMeasurement( void); static COND_COMM_STATE_T rxGetSingleMeasurement( void ); static void enqueueSingleMeasurement(TEENSY_SENSOR_INDEX_T sensorNum); static COND_PARSE_STATUS parseMeasurementSettings( const U08 *buffer, U32 len ); static COND_PARSE_STATUS parseEEPROMdata( const U08 *buffer, U32 len ); static COND_PARSE_STATUS parseConductivityMeasurements( const U08 *buffer, U32 len ); static U32 getTeensyCondId( CONDUCTIVITY_SENSORS_T sensorId ); static void calculateConductivity( TEENSY_SENSOR_INDEX_T sensorNum ); static void calculateTemperature( TEENSY_SENSOR_INDEX_T sensorNum ); /*********************************************************************//** * @brief * The initConductivityTeensy function initializes ConductivityTeensy unit * @details \b Inputs: none * @details \b Outputs: ConductivityTeensy unit variables initialized * @return none *************************************************************************/ void initConductivityTeensy( void ) { condCommState = COND_COMM_STATE_IDLE; condResponseTime = 0; condReceiptCounter = 0; condTransmitCounter = 0; condAutomatedDataPolling = FALSE; condWriteCommandInProgress = FALSE; condReadCommandInProgress = FALSE; condBulkWriteAndReadInProgress = FALSE; condWriteCmdRspnsRcvd = FALSE; memset( &condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); memset( &condWriteResponseBuffer, 0, COND_WRITE_RSP_BUFFER_LEN ); memset( &condTxBuffer, 0, COND_TX_BUFFER_LEN ); memset( &condRxBuffer, 0, COND_RX_BUFFER_LEN ); memset( &condCmdQ, 0, COND_CMD_Q_LEN ); memset( &condUpdateSettingStatus, 0, MAX_COND_MST_PARAM_IDX ); memset( &condRawMeasurement, 0, MAX_TEENSY_SENSOR ); memset( &condCalculatedMeasurement, 0, MAX_TEENSY_SENSOR ); memset( &condCoeff, 0, MAX_TEENSY_SENSOR ); queueCount = 0; queueRearIndex = 0; queueFrontIndex = 0; currentCmd = TEENSY_CMD_INIT_SENSOR; condInitStatus = COND_INIT_STATUS_UNITIALIZED; condUpdateEEPROMstatus = COND_UPDATE_EEPROM_STATUS_UNITIALIZED; condStopMeasurementSatus = 0; currentSelectedSensor = TEENSY_SENSOR_0; initCondDMAchannels(); //TODO Clean up after testing. // add init conductivity commands enqueue( TEENSY_CMD_STOP_MEASUREMENT ); enqueue( TEENSY_CMD_INIT_SENSOR ); enqueue( TEENSY_CMD_GET_INIT_STATUS ); // initEEPROMdata( ); // initMeasurementSettings( ); // enqueueSingleMeasurement(2); } /*********************************************************************//** * @brief * The initCondDMAchannels function configures DMA based SCI communication. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ static void initCondDMAchannels( void ) { memset( &condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); memset( &condWriteResponseBuffer, 0, COND_WRITE_RSP_BUFFER_LEN ); // Enable interrupt notifications for FPGA serial port sciEnableNotification( sciREG, SCI_OE_INT | SCI_FE_INT ); // Assign DMA channels to h/w DMA requests dmaReqAssign( DMA_CH1, SCI_RECEIVE_DMA_REQUEST ); dmaReqAssign( DMA_CH3, SCI_TRANSMIT_DMA_REQUEST ); // Set DMA channel priorities dmaSetPriority( DMA_CH1, HIGHPRIORITY ); dmaSetPriority( DMA_CH3, LOWPRIORITY ); // Enable DMA block transfer complete interrupts dmaEnableInterrupt( DMA_CH1, BTC ); dmaEnableInterrupt( DMA_CH3, BTC ); // Initialize Conductivity DMA Write Control Record condDMAWriteControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) condDMAWriteControlRecord.SADD = ( U32 )condWriteCmdBuffer; // Transfer source address condDMAWriteControlRecord.DADD = ( U32 )( &( sciREG->TD ) ); // Dest. is SCI xmit register condDMAWriteControlRecord.CHCTRL = 0; // No chaining condDMAWriteControlRecord.ELCNT = 1; // Frame is 1 element condDMAWriteControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known condDMAWriteControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte for read condDMAWriteControlRecord.WRSIZE = ACCESS_8_BIT; // Element size is 1 byte for write condDMAWriteControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer condDMAWriteControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment condDMAWriteControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed condDMAWriteControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off condDMAWriteControlRecord.ELSOFFSET = 0; // Not used condDMAWriteControlRecord.ELDOFFSET = 0; // Not used condDMAWriteControlRecord.FRSOFFSET = 0; // Not used condDMAWriteControlRecord.FRDOFFSET = 0; // Not used // Initialize Conductivity DMA Write Response Control Record condDMAWriteRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) condDMAWriteRespControlRecord.SADD = ( U32 )( &( sciREG->RD ) ); // Source is SCI recv register condDMAWriteRespControlRecord.DADD = ( U32 )condWriteResponseBuffer; // Transfer destination address condDMAWriteRespControlRecord.CHCTRL = 0; // No chaining condDMAWriteRespControlRecord.ELCNT = 1; // Frame is 1 element condDMAWriteRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known condDMAWriteRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte condDMAWriteRespControlRecord.WRSIZE = ACCESS_8_BIT; // condDMAWriteRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer condDMAWriteRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed condDMAWriteRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment condDMAWriteRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off condDMAWriteRespControlRecord.ELDOFFSET = 0; // Not used condDMAWriteRespControlRecord.ELSOFFSET = 0; // Not used condDMAWriteRespControlRecord.FRDOFFSET = 0; // Not used condDMAWriteRespControlRecord.FRSOFFSET = 0; // Not used // There should not be any data pending yet consumeUnexpectedConductivityData(); } /*********************************************************************//** * @brief * The initEEPROMdata function populates eePromDataTX structure and enqueues * update EEPROM data command in the the command queue. * @details \b Inputs: none * @details \b Outputs: eePromDataTX : EEPROM data to be updated on Teensy. * @return none *************************************************************************/ static void initEEPROMdata( void ) { // TODO Update real values in eePromDataTX eePromDataTX.doubleValue[ 0 ] = 0.0; eePromDataTX.doubleValue[ 1 ] = 0.0; eePromDataTX.doubleValue[ 2 ] = 0.0; eePromDataTX.doubleValue[ 3 ] = 0.0; eePromDataTX.doubleValue[ 4 ] = 0.0; eePromDataTX.doubleValue[ 5 ] = 0.0; eePromDataTX.doubleValue[ 6 ] = 0.0; eePromDataTX.doubleValue[ 7 ] = 0.0; eePromDataTX.floatValue[ 0 ] = 0.0; eePromDataTX.floatValue[ 1 ] = 0.0; eePromDataTX.floatValue[ 2 ] = 0.0; eePromDataTX.floatValue[ 3 ] = 0.0; eePromDataTX.floatValue[ 4 ] = 0.0; eePromDataTX.floatValue[ 5 ] = 0.0; eePromDataTX.floatValue[ 6 ] = 0.0; eePromDataTX.floatValue[ 7 ] = 0.0; eePromDataTX.floatValue[ 8 ] = 0.0; eePromDataTX.floatValue[ 8 ] = 0.0; eePromDataTX.floatValue[ 10 ] = 0.0; eePromDataTX.floatValue[ 11 ] = 0.0; eePromDataTX.floatValue[ 12 ] = 0.0; eePromDataTX.floatValue[ 13 ] = 0.0; eePromDataTX.floatValue[ 14 ] = 0.0; eePromDataTX.floatValue[ 15 ] = 0.0; enqueue( TEENSY_CMD_UPDATE_EEPROM_DATA ); } /*********************************************************************//** * @brief * The initMeasurementSettings function populates measurementSettingsTX structure and enqueues * update measurement settings command in the the command queue. * @details \b Inputs:none * @details \b Outputs:measurementSettingsTX - Measurement settings data to updated on Teensy. * @return none *************************************************************************/ static void initMeasurementSettings( void ) { // TODO Update real values in measurementSettingsTX measurementSettingsTX.SinFreq = 11000.0; measurementSettingsTX.DacVoltPP = 400.0; measurementSettingsTX.BiasVolt = 200.0; measurementSettingsTX.HstiaRtiaSel = 7; measurementSettingsTX.AdcPgaGain = 2; measurementSettingsTX.DftNum = 256; measurementSettingsTX.ADCAvgNum = 16; enqueue( TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS ); } /*********************************************************************//** * @brief * The execConductivityTeensy function manages incoming data exchanges with * the Teensy board over UART. * @details \b Inputs: condCommState - Current state. * @details \b Outputs: condCommState - Next state. * @return none *************************************************************************/ void execConductivityTeensy( void ) { switch ( condCommState ) { case COND_COMM_STATE_IDLE: condCommState = handleConductivityIdle(); break; case COND_COMM_STATE_TX: condCommState = handleConductivityTX(); break; case COND_COMM_STATE_RX: condCommState = handleConductivityRX(); break; case COND_COMM_STATE_FAILED: condCommState = handleFailedState(); break; default: SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, ( U32 )condCommState ) break; } } /*********************************************************************//** * @brief * The handleConductivityIdle handles the command queue and transitions to the respective * comm state. * @details \b Inputs: condAutomatedDataPolling * @details \b Outputs: none * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T handleConductivityIdle( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_IDLE; // If we are in idle, we are expecting new data next cycle. Clear buffers memset( &condTxBuffer, 0, COND_TX_BUFFER_LEN ); memset( &condRxBuffer, 0, COND_RX_BUFFER_LEN ); memset( &condWriteResponseBuffer, 0, COND_WRITE_RSP_BUFFER_LEN ); memset( &condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); if ( !isQueueEmpty() ) { dequeue(); state = COND_COMM_STATE_TX; } else { // If queue is empty, q automated polling data cmd // otherwise, we are already polling data, move to recv next data packet if ( ( condAutomatedDataPolling == TRUE ) && ( currentCmd != TEENSY_CMD_STOP_MEASUREMENT ) ) { condWriteCommandInProgress = TRUE; // set to TRUE for recv interrupt to trigger with no sent msg setupConductivityDMAForWriteResp( teensyCmdMap[ currentCmd ].rxSize ); startConductivityDMAReceiptOfWriteResp(); state = COND_COMM_STATE_RX; } else { condAutomatedDataPolling = TRUE; enqueue( TEENSY_CMD_START_MEASUREMENT ); } } return state; } /*********************************************************************//** * @brief * The handleConductivityTX handles the transmission of data over UART * to the Teensy board. * @details \b Inputs: currentCmd - Current command being executed (transmitted). * @details \b Outputs: none * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T handleConductivityTX( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; switch ( currentCmd ) { case TEENSY_CMD_INIT_SENSOR: state = txInitSensor(); break; case TEENSY_CMD_GET_INIT_STATUS: state = txGetInitStatus(); break; case TEENSY_CMD_UPDATE_EEPROM_DATA: state = txUpdateEEPROMdata( ); break; case TEENSY_CMD_GET_EEPROM_DATA: state = txGetEEPROMdata(); break; case TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS: state = txUpdateMeasurementSettings( ); break; case TEENSY_CMD_GET_MEASUREMENT_SETTINGS: state = txGetMeasurementSettings(); break; case TEENSY_CMD_START_MEASUREMENT: state = txStartMeasurements(); break; case TEENSY_CMD_STOP_MEASUREMENT: state = txStopMeasurement(); break; case TEENSY_CMD_GET_ALL_MEASUREMENTS: state = txGetAllMeasurements(); break; case TEENSY_CMD_GET_SINGLE_MEASUREMENT: state = txGetSingleMeasurement(); break; default: break; } return state; } /*********************************************************************//** * @brief * The handleConductivityRX handles the receiving of data over UART * to the Teensy board. * @details \b Inputs: currentCmd - Current command for which response is * being received. * @details \b Outputs: none * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T handleConductivityRX( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; switch ( currentCmd ) { case TEENSY_CMD_INIT_SENSOR: state = rxInitSensor(); break; case TEENSY_CMD_GET_INIT_STATUS: state = rxGetInitStatus(); break; case TEENSY_CMD_UPDATE_EEPROM_DATA: state = rxUpdateEEPROMdata( ); break; case TEENSY_CMD_GET_EEPROM_DATA: state = rxGetEEPROMdata(); break; case TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS: state = rxUpdateMeasurementSettings( ); break; case TEENSY_CMD_GET_MEASUREMENT_SETTINGS: state = rxGetMeasurementSettings(); break; case TEENSY_CMD_START_MEASUREMENT: state = rxStartMeasurements(); break; case TEENSY_CMD_STOP_MEASUREMENT: state = rxStopMeasurement(); break; case TEENSY_CMD_GET_ALL_MEASUREMENTS: state = rxGetAllMeasurements(); break; case TEENSY_CMD_GET_SINGLE_MEASUREMENT: state = rxGetSingleMeasurement( ); break; default: break; } return state; } /*********************************************************************//** * @brief * The handleFailedState function handles failure or errors of the states. * @details \b Inputs: currentCmd - Current command being executed. * The error occurred during TX or RX phase of this command. * @details \b Outputs: none * @details \b Outputs: none * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T handleFailedState( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_FAILED; switch ( currentCmd ) { case TEENSY_CMD_INIT_SENSOR: break; case TEENSY_CMD_GET_INIT_STATUS: break; case TEENSY_CMD_UPDATE_EEPROM_DATA: break; case TEENSY_CMD_GET_EEPROM_DATA: break; case TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS: break; case TEENSY_CMD_GET_MEASUREMENT_SETTINGS: break; case TEENSY_CMD_START_MEASUREMENT: break; case TEENSY_CMD_STOP_MEASUREMENT: break; case TEENSY_CMD_GET_ALL_MEASUREMENTS: break; case TEENSY_CMD_GET_SINGLE_MEASUREMENT: break; default: break; } return state; } /*********************************************************************//** * @brief * The consumeUnexpectedConductivityData function checks to see if a byte is sitting in * the SCI received data register and consumes the byte if found. * @details \b Inputs: SCI FLR register * @details \b Outputs: SCI errors cleared, unexpected byte consumed * @return none *************************************************************************/ static void consumeUnexpectedConductivityData( void ) { // Clear any errors sciRxError( sciREG ); // If a byte is pending read, read it if ( sciIsRxReady( sciREG ) != 0 ) { sciReceiveByte( sciREG ); } } /*********************************************************************//** * @brief * The setupConductivityDMAForWriteCmd function sets the byte count for the * next DMA write command. * @details \b Inputs: condDMAWriteControlRecord * @details \b Outputs: number of bytes for next Teensy command is set * @param bytes2Transmit number of bytes to be transmitted via DMA to the Teensy. * @return none *************************************************************************/ static void setupConductivityDMAForWriteCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= COND_TX_BUFFER_LEN ) { condDMAWriteControlRecord.FRCNT = bytes2Transmit; } } /*********************************************************************//** * @brief * The startConductivityDMAWriteCmd function initiates the DMA transmit for * the next DMA write command to the Teensy. * @details \b Inputs: condDMAWriteControlRecord * @details \b Outputs: DMA write command is initiated * @return none *************************************************************************/ static void startConductivityDMAWriteCmd( void ) { dmaSetCtrlPacket( DMA_CH3, condDMAWriteControlRecord ); dmaSetChEnable( DMA_CH3, DMA_HW ); setSCIDMATransmitInterrupt(); } /*********************************************************************//** * @brief * The setupConductivityDMAForWriteResp function sets the expected byte count for the * next DMA write command response from the Teensy. * @details \b Inputs: none * @details \b Outputs: condDMAWriteRespControlRecord * @param bytes2Receive number of bytes expected to be transmitted via DMA from Teensy * @return none *************************************************************************/ static void setupConductivityDMAForWriteResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= COND_RX_BUFFER_LEN ) { condDMAWriteRespControlRecord.FRCNT = bytes2Receive; } } /*********************************************************************//** * @brief * The startConductivityDMAReceiptOfWriteResp function initiates readiness of the DMA * receiver for the next DMA write command response from the Teensy. * @details \b Inputs: condDMAWriteRespControlRecord * @details \b Outputs: DMA write command response is made ready to be received from * the Teensy * @return none *************************************************************************/ static void startConductivityDMAReceiptOfWriteResp( void ) { dmaSetCtrlPacket( DMA_CH1, condDMAWriteRespControlRecord ); dmaSetChEnable( DMA_CH1, DMA_HW ); setSCIDMAReceiveInterrupt(); } /*********************************************************************//** * @brief * The signalConductivityReceiptCompleted function increments a counter to indicate * that another DMA receipt from the Teensy has completed and sets comm flags * indicating pending response from Teensy is completed. * @details \b Inputs: none * @details \b Outputs: condReceiptCounter, condWriteCommandInProgress, * condWriteCmdRspnsRcvd * @return none *************************************************************************/ void signalConductivityReceiptCompleted( void ) { condReceiptCounter++; // Did Conductivity Ack last command? if ( TRUE == condWriteCommandInProgress ) { condWriteCommandInProgress = FALSE; condWriteCmdRspnsRcvd = TRUE; } } /*********************************************************************//** * @brief * The signalConductivityTransmitCompleted function increments a counter to indicate * that another DMA transmit to the Teensy has completed. * @details \b Inputs: none * @details \b Outputs: condTransmitCounter * @return none *************************************************************************/ void signalConductivityTransmitCompleted( void ) { condTransmitCounter++; } /*********************************************************************//** * @brief * The isQueueFull checks whether the queue is full and * if it is full, it will return a TRUE. * @details Inputs: queueCount * @details Outputs: none * @return TRUE if queue is full. Otherwise, FALSE. *************************************************************************/ static BOOL isQueueFull ( void ) { BOOL isFull = FALSE; if ( queueCount >= COND_CMD_Q_LEN - 1 ) { isFull = TRUE; } return isFull; } /*********************************************************************//** * @brief * The isQueueEmpty checks whether the queue is empty and * if it is empty, it will return a TRUE. * @details Inputs: queueCount * @details Outputs: none * @return TRUE if queue is empty. Otherwise, FALSE. *************************************************************************/ static BOOL isQueueEmpty ( void ) { BOOL isEmpty = TRUE; if ( queueCount > 0 ) { isEmpty = FALSE; } return isEmpty; } /*********************************************************************//** * @brief * The enqueue function adds a cmd from the cmd queue if it is not full. * @details Inputs: condCmdQ[], queueRearIndex, queueCount * @details Outputs: condCmdQ[], queueRearIndex, queueCount * @param cmd the Cmd ID to be queue'd * @return none *************************************************************************/ static BOOL enqueue ( TEENSY_CMD_INDEX_T cmd ) { BOOL result = FALSE; _disable_IRQ(); if ( FALSE == isQueueFull() ) { queueCount++; condCmdQ[ queueRearIndex ] = cmd; queueRearIndex = INC_WRAP( queueRearIndex, 0, COND_CMD_Q_LEN - 1 ); result = TRUE; } _enable_IRQ(); return result; } /*********************************************************************//** * @brief * The dequeue function removes a cmd from the cmd queue if it is not empty. * @details Inputs: condCmdQ[], queueFrontIndex, queueCount * @details Outputs: condCmdQ[], queueFrontIndex, queueCount, currentCmd * @return none *************************************************************************/ static void dequeue( void ) { U32 tempIndex; _disable_IRQ(); tempIndex = queueFrontIndex; if ( FALSE == isQueueEmpty() ) { queueFrontIndex = INC_WRAP( queueFrontIndex, 0, COND_CMD_Q_LEN - 1 ); currentCmd = condCmdQ [ tempIndex ]; } if ( queueCount > 0 ) { queueCount--; } _enable_IRQ(); } /*********************************************************************//** * @brief * The txTeensyWriteCmd function writes a command (with optional parameters) to the write buffer. * @details \b Inputs: teensyCmdMap, condTxBuffer * @details \b Outputs: condWriteCmdBuffer * @param cmdIndex Index of the command in teensyCmd[]. * @param param Optional parameter string to append after the command. * @return TRUE if the command was successfully written to the write buffer, FALSE otherwise. *************************************************************************/ static BOOL txTeensyWriteCmd( TEENSY_CMD_INDEX_T cmdIndex, const U08* param ) { const U08* baseCmd = ( const U08* )teensyCmdMap[ cmdIndex ].teensyCMD; BOOL success = FALSE; U16 written = 0; // Format command with optional parameter if ( ( NULL != param ) && ( strlen( ( const char* )param ) > 0 ) ) { written = snprintf( ( char* )condTxBuffer, COND_TX_BUFFER_LEN, "%s,%s", ( const char* )baseCmd, ( const char* )param ); } else { written = snprintf( ( char* )condTxBuffer, COND_TX_BUFFER_LEN, "%s", ( const char* )baseCmd ); } if ( written > 0 ) { // Clear the DMA write comand buffer memcpy( &condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); // Load the DMA write command buffer with contents of TX buffer. memcpy( &condWriteCmdBuffer, &condTxBuffer, written ); success = TRUE; condWriteCommandInProgress = TRUE; setupConductivityDMAForWriteCmd( written ); setupConductivityDMAForWriteResp( teensyCmdMap[ cmdIndex ].rxSize ); startConductivityDMAReceiptOfWriteResp(); startConductivityDMAWriteCmd(); } return success; } /*********************************************************************//** * @brief * The rxTeensyReadRsp functions writes the response of a command in the response buffer. * @details \b Inputs: condWriteResponseBuffer * @details \b Outputs: condRxBuffer * @param cmdIndex Index of the command in teensyCmd[]. * @return TRUE if the response was successfully written to the response buffer, * FALSE otherwise. *************************************************************************/ static BOOL rxTeensyReadRsp( TEENSY_CMD_INDEX_T cmdIndex ) { BOOL success = FALSE; if ( TRUE == condWriteCmdRspnsRcvd ) { memcpy( &condRxBuffer, &condWriteResponseBuffer, teensyCmdMap[ cmdIndex ].rxSize ); condWriteCmdRspnsRcvd = FALSE; success = TRUE; } // Should not be any data received at this time consumeUnexpectedConductivityData(); return success; } /*********************************************************************//** * @brief * The txInitSensor function sends initialize sensors command to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txInitSensor( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If the init sensor cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_INIT_SENSOR, NULL ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the init status state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxInitSensor function handles received response of initialize sensor command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condInitStatus - Sensor Initialization status. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxInitSensor( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; COND_INIT_STATUS_T initStatusInProgress = COND_INIT_STATUS_FAILED; // set to fail for testing COND_INIT_STATUS_T initStatusInitialized = COND_INIT_STATUS_FAILED; // if data populates BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_INIT_SENSOR ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer initStatusInProgress = ( COND_INIT_STATUS_T )condRxBuffer[ 0 ]; initStatusInitialized = ( COND_INIT_STATUS_T )condRxBuffer[ 1 ]; // Store the init status condInitStatus = initStatusInitialized; switch ( condInitStatus ) { case COND_INIT_STATUS_UNITIALIZED: break; case COND_INIT_STATUS_IN_PROGRESS: state = COND_COMM_STATE_IDLE; break; case COND_INIT_STATUS_INITIALIZED: state = COND_COMM_STATE_IDLE; break; case COND_INIT_STATUS_FAILED: default: state = COND_COMM_STATE_IDLE; break; } } else if ( TRUE == didTimeout( condResponseTime, COND_STATUS_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txGetInitStatus function sends get sensor initialization status command * to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @param none * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txGetInitStatus( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If the get init status cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_GET_INIT_STATUS, NULL ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the init status state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxGetInitStatus function handles received response of get sensor * initialization status command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condInitStatus - Sensor Initialization status. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxGetInitStatus( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_GET_INIT_STATUS ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&condInitStatus, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_GET_INIT_STATUS ].rxSize ); // condInitStatus = ( cOND_INIT_STATUS_T )condRxBuffer[ 0 ]; switch ( condInitStatus ) { case COND_INIT_STATUS_UNITIALIZED: break; case COND_INIT_STATUS_IN_PROGRESS: state = COND_COMM_STATE_IDLE; break; case COND_INIT_STATUS_INITIALIZED: state = COND_COMM_STATE_IDLE; break; case COND_INIT_STATUS_FAILED: default: state = COND_COMM_STATE_IDLE; break; } } else if ( TRUE == didTimeout( condResponseTime, COND_STATUS_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txUpdateEEPROMdata function sends update EEPRPM data command to Teensy. * @details \b Inputs: eePromDataTX - EEPROM data to be updated in Teensy. * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txUpdateEEPROMdata( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // Format EEPROM data into a string U08 paramStr[ 256 ]; U16 offset = 0; U16 i = 0; // Pack the command and EEPROM data for ( i = 0; i < DOUBLE_COUNT; ++i ) { offset += snprintf( ( char* )( paramStr + offset ), sizeof( paramStr ) - offset, "%.6f,", eePromDataTX.doubleValue[ i ] ); } for ( i = 0; i < FLOAT_COUNT; ++i ) { offset += snprintf( ( char* )( paramStr + offset ), sizeof( paramStr ) - offset, "%.6f,", eePromDataTX.floatValue[ i ] ); } // Remove trailing comma if needed if ( ( offset > 0 ) && ( paramStr[ offset - 1 ] == ',' ) ) { paramStr[ offset - 1 ] = '\0'; } // Transmit the command and the EEPROM data and check if it was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_UPDATE_EEPROM_DATA, paramStr ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the EEPROM update status state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxUpdateEEPROMdata function handles received response of update EEPRPM data command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condUpdateEEPROMstatus - Update EEPRPM data status. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxUpdateEEPROMdata( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_UPDATE_EEPROM_DATA ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&condUpdateEEPROMstatus, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_UPDATE_EEPROM_DATA ].rxSize ); // condUpdateEEPROMstatus = ( CONDUCTIVITY_UPDATE_EEPROM_STATUS_T )condRxBuffer[ 0 ]; // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else if ( TRUE == didTimeout( condResponseTime, COND_STATUS_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txGetEEPROMdata function sends get EEPROM data command to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txGetEEPROMdata( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If the get EEPROM data cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_GET_EEPROM_DATA, NULL ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the EEPROM data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxGetEEPROMdata function handles received response of get EEPROM data command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: eePromDataRX - Received EEPROM data. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxGetEEPROMdata( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; state = COND_COMM_STATE_IDLE; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_GET_EEPROM_DATA ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&eePromDataRX, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_GET_EEPROM_DATA ].rxSize ); // parseStatus = parseEEPROMdata( condRxBuffer, COND_RX_BUFFER_LEN ); // Check if parsing was done successfully if ( COND_PARSE_SUCCESS == parseStatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } } else if ( TRUE == didTimeout( condResponseTime, COND_DATA_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txUpdateMeasurementSettings function sends update measurement settings command * to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txUpdateMeasurementSettings( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; U08 paramStr[ 128 ]; snprintf( ( char * )paramStr, sizeof( paramStr ), "%.4f,%.4f,%.4f,%lu,%lu,%lu,%lu", measurementSettingsTX.SinFreq, measurementSettingsTX.DacVoltPP, measurementSettingsTX.BiasVolt, measurementSettingsTX.HstiaRtiaSel, measurementSettingsTX.AdcPgaGain, measurementSettingsTX.DftNum, measurementSettingsTX.ADCAvgNum ); // If update measurement settings cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS, paramStr ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the EEPROM data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxUpdateMeasurementSettings function handles received response of * update measurement settings command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condUpdateSettingStatus - Update measurement settings status. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxUpdateMeasurementSettings( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&condUpdateSettingStatus, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS ].rxSize ); // updateSettingStatus = ( CONDUCTIVITY_UPDATE_MST_STATUS_T )condTxBuffer[ 0 ]; // Move to TX state to update the next param. state = COND_COMM_STATE_TX; } else if ( TRUE == didTimeout( condResponseTime, COND_STATUS_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txGetMeasurementSettings function sends get measurement settings command * to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txGetMeasurementSettings( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If get measurement settings cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_GET_MEASUREMENT_SETTINGS, NULL ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the EEPROM data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxGetMeasurementSettings function handles received response of * get measurement settings command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: measurementSettingsRX - Received Measurement Settings * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxGetMeasurementSettings( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; state = COND_COMM_STATE_IDLE; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_GET_MEASUREMENT_SETTINGS ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&measurementSettingsRX, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_GET_MEASUREMENT_SETTINGS ].rxSize ); // parseStatus = parseMeasurementSettings( condRxBuffer, COND_RX_BUFFER_LEN ); // Check if parsing was done successfully if ( COND_PARSE_SUCCESS == parseStatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } } else if ( TRUE == didTimeout( condResponseTime, COND_DATA_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txStartMeasurements function sends start measurements command to the Teensy. * This command will start the automated Conductivity measurements polling. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @details \b Outputs: condAutomatedDataPolling set to TRUE. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txStartMeasurements( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If start measurement settings cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_START_MEASUREMENT, NULL ) ) { // Set the flag to indicate that automated conductivity data polling has started. condAutomatedDataPolling = TRUE; // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the measurement data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxStartMeasurements function handles received response of start measurements command. * @details \b Inputs: condResponseTime - Time at which command was transmitted or * previous conductivity measurements data was received. * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condRawMeasurement - Raw Conductivity Measurements (includes impedance and rtd) * @details \b Outputs: condCalculatedMeasurement - Calculated Conductivity and temperature. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxStartMeasurements( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_START_MEASUREMENT ); if ( TRUE == recvComplete ) { // Get the time stamp for next sensor packet condResponseTime = getMSTimerCount(); // Read the data from the receive buffer parseStatus = parseConductivityMeasurements( condRxBuffer, COND_RX_BUFFER_LEN ); // Check if parsing was done successfully if ( COND_PARSE_SUCCESS == parseStatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_IDLE; } } else if ( TRUE == didTimeout( condResponseTime, COND_DATA_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txStopMeasurement function sends stop measurements command to the Teensy. * This command will stop the automated polling of conductivity measurements data. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @details \b Outputs: condAutomatedDataPolling set to FALSE. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txStopMeasurement( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If get measurement settings cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_STOP_MEASUREMENT, NULL ) ) { // Set the flag to indicate that automated conductivity data polling has stopped. condAutomatedDataPolling = FALSE; // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the measurement data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxStopMeasurement function handles received response of stop measurements command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condStopMeasurementSatus - Stop measurement status * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxStopMeasurement( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_STOP_MEASUREMENT ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer memcpy(&condStopMeasurementSatus, &condRxBuffer, teensyCmdMap[ TEENSY_CMD_STOP_MEASUREMENT ].rxSize ); // Check if parsing was done successfully if ( TRUE == condStopMeasurementSatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_IDLE; } } else if ( TRUE == didTimeout( condResponseTime, COND_STATUS_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txGetAllMeasurements function sends command to get measurements of all sensors * connected to the Teensy. * @details \b Inputs: none * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txGetAllMeasurements( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; // If get measurement settings cmd was sent successfully if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_GET_ALL_MEASUREMENTS, NULL ) ) { // Get the current time condResponseTime = getMSTimerCount(); // Go to receive state to receive the measurement data state = COND_COMM_STATE_RX; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } return state; } /*********************************************************************//** * @brief * The rxGetAllMeasurements function handles received response of * get all sensor measurements command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condRawMeasurement - Raw Conductivity Measurements (includes impedance and rtd) * @details \b Outputs: condCalculatedMeasurement - Calculated Conductivity and temperature. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxGetAllMeasurements( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_GET_ALL_MEASUREMENTS ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer parseStatus = parseConductivityMeasurements( condRxBuffer, COND_RX_BUFFER_LEN ); // Check if parsing was done successfully if ( COND_PARSE_SUCCESS == parseStatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } } else if ( TRUE == didTimeout( condResponseTime, COND_DATA_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The txGetSingleMeasurement function sends get single sensor measurement command * to the Teensy. * @details \b Inputs: currentSelectedSensor - Sensor number to be read. * @details \b Outputs: condResponseTime - Time at which command was transmitted. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T txGetSingleMeasurement( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_TX; U08 paramStr[ 8 ]; snprintf( ( char* )paramStr, sizeof( paramStr ), "%d", currentSelectedSensor ); // Assumes sensor has already been selected if ( TRUE == txTeensyWriteCmd( TEENSY_CMD_GET_SINGLE_MEASUREMENT, paramStr ) ) { // Get the current time condResponseTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The rxGetSingleMeasurement function handles received response of * get single sensor measurement command. * @details \b Inputs: condResponseTime - Time at which command was transmitted, * @details \b Inputs: condRxBuffer - Received response buffer * @details \b Outputs: condRawMeasurement - Raw Conductivity Measurements (includes impedance and rtd) * @details \b Outputs: condCalculatedMeasurement - Calculated Conductivity and temperature. * @return state - Next state. *************************************************************************/ static COND_COMM_STATE_T rxGetSingleMeasurement( void ) { COND_COMM_STATE_T state = COND_COMM_STATE_RX; // Check if a response is received in the RX buffer BOOL recvComplete = rxTeensyReadRsp( TEENSY_CMD_GET_SINGLE_MEASUREMENT ); if ( TRUE == recvComplete ) { // Reset the timer for next use. condResponseTime = 0; // Read the data from the receive buffer COND_PARSE_STATUS parseStatus = parseConductivityMeasurements( condRxBuffer, COND_RX_BUFFER_LEN ); // Check if parsing was done successfully if ( COND_PARSE_SUCCESS == parseStatus ) { // Go to the idle state to execute next cmd in the queue state = COND_COMM_STATE_IDLE; } else { // Go to failed state state = COND_COMM_STATE_FAILED; } } else if ( TRUE == didTimeout( condResponseTime, COND_DATA_TIMEOUT_MS ) ) { // Go to failed state state = COND_COMM_STATE_FAILED; } else { // Do Nothing. Wait until we either receive a response OR timeout happens. } return state; } /*********************************************************************//** * @brief * The enqueueSingleMeasurement function updates current select sensor in format * acceptable to Teensy and enqueues get single measurement command. * @details \b Inputs : none * @details \b Outputs: currentSelectedSensor - Current Selected Sensor indexed 1 to 6. * @param sensorNum - Teensy sensor index * @return none *************************************************************************/ static void enqueueSingleMeasurement(TEENSY_SENSOR_INDEX_T sensorNum) { // Sensors are indexed 1 to 6 in Teensy. So send (sensorNum + 1) as parameter. currentSelectedSensor = sensorNum + 1; // Enqueue get single measurement command. enqueue(TEENSY_CMD_GET_SINGLE_MEASUREMENT); } /*********************************************************************//** * @brief * The parseMeasurementSettings Reads measurement settings from buffer and * stores in measurementSettingsRX. * @details \b Inputs : none * @details \b Outputs: measurementSettingsRX - Received Measurement Settings * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return COND_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static COND_PARSE_STATUS parseMeasurementSettings( const U08 *buffer, U32 len ) { COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; U32 expectedDataLength = sizeof( COND_MEASUREMENT_SETTINGS_T ); // Validate buffer if ( buffer == NULL ) { parseStatus = COND_PARSE_ERROR_NULL_BUFFER; } else if ( len != expectedDataLength ) { parseStatus = COND_PARSE_ERROR_INVALID_LENGTH; } else { // Parse and store the data memcpy(&measurementSettingsRX, buffer, expectedDataLength ); parseStatus = COND_PARSE_SUCCESS; } return parseStatus; } /*********************************************************************//** * @brief * The parseEEPROMdata Reads EEPROM data from buffer and * stores in eePromDataRX. * @details \b Inputs : none * @details \b Outputs: eePromDataRX - Received EEPROM data * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return COND_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static COND_PARSE_STATUS parseEEPROMdata( const U08 *buffer, U32 len ) { COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; U32 expectedDataLength = sizeof( COND_EEPROM_DATA_T ); // Validate buffer if ( buffer == NULL) { parseStatus = COND_PARSE_ERROR_NULL_BUFFER; } // Validate buffer length else if ( len != expectedDataLength ) { parseStatus = COND_PARSE_ERROR_INVALID_LENGTH; } else { // Parse and Store the data memcpy(&eePromDataRX, buffer, expectedDataLength ); parseStatus = COND_PARSE_SUCCESS; } return parseStatus; } /*********************************************************************//** * @brief * The parseConductivityMeasurements Reads Conductivity Measurements / Sensor readings * from buffer and stores in condRawMeasurement. * Calculates the conductivity and temperature and stores in condCalculatedMeasurement. * @details \b Inputs : none * @details \b Outputs: condRawMeasurement - Raw Conductivity Measurements (includes impedance and rtd) * @details \b Outputs: condCalculatedMeasurement - Calculated Conductivity and temperature. * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return COND_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static COND_PARSE_STATUS parseConductivityMeasurements( const U08 *buffer, U32 len ) { COND_PARSE_STATUS parseStatus = COND_PARSE_NONE; COND_SENSOR_DATA_T tempSensor; // Validate buffer if ( NULL == buffer ) { parseStatus = COND_PARSE_ERROR_INVALID_SENSOR_NUM; } else { // Read the sensor data temporarily memcpy( &tempSensor, buffer, teensyCmdMap[ currentCmd ].rxSize ); // Check if the received sensor number is valid. Sensors are numbered 1 to 6 on Teensy. if ( ( tempSensor.sensorNum < 1 ) || ( tempSensor.sensorNum > MAX_TEENSY_SENSOR ) ) { parseStatus = COND_PARSE_ERROR_INVALID_SENSOR_NUM; } else { // Store Raw value in array index for position ( sensorNum - 1 ) condRawMeasurement[ tempSensor.sensorNum - 1 ] = tempSensor; // Calculate and store Conductivity from raw values calculateConductivity( tempSensor.sensorNum - 1 ); // Calculate and store Temperature from raw values. calculateTemperature( tempSensor.sensorNum - 1 ); parseStatus = COND_PARSE_SUCCESS; } } return parseStatus; } /*********************************************************************//** * @brief * The getTeensyCondId function maps Sensor Index to Conductivity Sensors. * @details \b Inputs: * @details \b Outputs: * @param sensorId - Id of DD Conductivity Sensors * @return sensorNum - Sensor Index. *************************************************************************/ static U32 getTeensyCondId( CONDUCTIVITY_SENSORS_T sensorId ) { U32 sensorNum = 0; switch ( sensorId ) { case P9_COND: sensorNum = TEENSY_SENSOR_0; break; case P18_COND: sensorNum = TEENSY_SENSOR_1; break; case D17_COND: sensorNum = TEENSY_SENSOR_2; break; case D27_COND: sensorNum = TEENSY_SENSOR_3; break; case D29_COND: sensorNum = TEENSY_SENSOR_4; break; case D43_COND: sensorNum = TEENSY_SENSOR_5; break; } return sensorNum; } /*********************************************************************//** * @brief * The getConductivityValue function gets the current calculated conductivity / impedance value. * @details \b Inputs: condCalculatedMeasurement * @details \b Outputs: none * @param sensor ID of conductivity sensor to get conductivity. * @return The current conductivity of a given conductivity sensor. *************************************************************************/ F32 getTeensyConductivityValue( CONDUCTIVITY_SENSORS_T sensorId ) { U32 sensorNum = getTeensyCondId( sensorId ); F32 result = 0.0F; if ( D74_COND != sensorId ) { result = ( F32 )condCalculatedMeasurement[ sensorNum ].Conductivity; } return result; } /*********************************************************************//** * @brief * The getTemperatureValue function gets the current conductivity sensor * temperature for a given conductivity sensor. * @details \b Inputs: condCalculatedMeasurement * @details \b Outputs: none * @param sensorId ID of conductivity sensor to get temperature. * @return The current temperature of a given conductivity sensor. *************************************************************************/ F32 getTeensyConductivityTemperatureValue( CONDUCTIVITY_SENSORS_T sensorId ) { U32 sensorNum = getTeensyCondId( sensorId ); F32 result = 0.0F; if ( D74_COND != sensorId ) { result = ( F32 )condCalculatedMeasurement[ sensorNum ].Temperature; } return result; } /*********************************************************************//** * @brief * The calculateConductivity function calculates the conductivity value. * @details \b Inputs: condCoeff - Conductivity Coefficients * @details \b Inputs: condRawMeasurement - Raw measurement values * @details \b Outputs: condCalculatedMeasurement - calculated conductivity value * @param sensorNum - Teensy sensor index value. * @return *************************************************************************/ static void calculateConductivity( TEENSY_SENSOR_INDEX_T sensorNum ) { F64 calculatedConductivity = 0.0; F64 B3 = condCoeff[ sensorNum ].B3; F64 B2 = condCoeff[ sensorNum ].B2; F64 B1 = condCoeff[ sensorNum ].B1; F64 B0 = condCoeff[ sensorNum ].B0; F64 R = condRawMeasurement[ sensorNum ].impRzMag; F64 Z = condRawMeasurement[ sensorNum ].rtdRzMag; calculatedConductivity = ( ( B3 * ( 1000.0 / R ) ) + ( B2 * ( Z / R ) ) + ( B1 * ( ( 100 * log( Z ) ) / R ) ) + B0 ); condCalculatedMeasurement[ sensorNum ].Conductivity = calculatedConductivity; } /*********************************************************************//** * @brief * The calculateTemperature function calculates the temperature values. * @details \b Inputs: condCoeff - Conductivity Coefficients * @details \b Inputs: condRawMeasurement - Raw measurement values * @details \b Outputs: condCalculatedMeasurement - calculated temperature value * @param sensorNum - Teensy sensor index value. * @return *************************************************************************/ static void calculateTemperature( TEENSY_SENSOR_INDEX_T sensorNum ) { F64 calculatedTemperature = 0.0; F64 A1 = condCoeff[ sensorNum ].A1; F64 A0 = condCoeff[ sensorNum ].A0; F64 Z = condRawMeasurement[ sensorNum ].rtdRzMag; calculatedTemperature = ( ( A1 * Z ) + A0 ); condCalculatedMeasurement[ sensorNum ].Temperature = calculatedTemperature; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/