/************************************************************************** * * 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" #define SCI_RECEIVE_DMA_REQUEST 38 ///< Serial port receive DMA request line. #define SCI_TRANSMIT_DMA_REQUEST 39 ///< Serial port transmit DMA request line. #define COND_WRITE_CMD_BUFFER_LEN 256 ///< Conductivity write command buffer byte length. #define COND_WRITE_RSP_BUFFER_LEN 8 ///< Conductivity write command response buffer byte length. #define COND_READ_CMD_BUFFER_LEN 8 ///< Conductivity read command buffer byte length. #define COND_READ_RSP_BUFFER_LEN 256 ///< Conductivity read command response buffer byte length. #define COND_CMD_Q_LEN 8 ///< Maximum number of cmds that can be queue'd. #define QUEUE_START_INDEX 0U ///< Queue start index. // ********** private data ********** static CONDUCTIVITY_COMM_STATE_T conductivityCommState = COND_COMM_STATE_IDLE; static CONDUCTIVITY_TX_STATE_T conductivityTXCommState = COND_COMM_STATE_SEND_CMD_INIT_SENSOR; static CONDUCTIVITY_RX_STATE_T conductivityRXCommState = COND_COMM_STATE_RCV_RSPNS_INIT_SENSOR; static U32 condReceiptCounter = 0; ///< Conductivity response receipt counter. static U32 condTransmitCounter = 0; ///< Conductivity command transmit counter. static BOOL condWriteCommandInProgress = FALSE; ///< Flag indicating an Conductivity write command is in progress. static BOOL condReadCommandInProgress = FALSE; ///< Flag indicating an Conductivity read command is in progress. static BOOL condBulkWriteAndReadInProgress = FALSE; ///< Flag indicating an Conductivity bulk write and read command are in progress. static BOOL condWriteCmdRspnsRcvd = FALSE; ///< Flag indicating a response to an Conductivity write command has been received. static BOOL condReadCmdRspnsRcvd = FALSE; ///< Flag indicating a response to an Conductivity read 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 condReadCmdBuffer[ COND_READ_CMD_BUFFER_LEN ]; ///< Conductivity read command buffer. Holds the next Conductivity read command to be transmitted. static U08 condReadResponseBuffer[ COND_READ_RSP_BUFFER_LEN ]; ///< Conductivity read command response buffer. Memory reserved to capture the response to the last Conductivity read command. // 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; // 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. static g_dmaCTRL condDMAReadControlRecord; ///< DMA record for controlling a DMA read command transmission from buffer. static g_dmaCTRL condDMAReadRespControlRecord; ///< DMA record for controlling a DMA read command reception to buffer. static CONDUCTIVITY_INIT_STATUS_T conductivityInitStatus; static CONDUCTIVITY_EEPROM_DATA_T conductivityEEPROMdata; static CONDUCTIVITY_MEASUREMENT_SETTINGS_T conductivityMeasurementSettings; static CONDUCTIVITY_SENSOR_DATA_T rawConductivityValues[ MAX_TEENSY_SENSOR ]; static CONDUCTIVITY_CALCULATED_MEASUREMENTS_T calculatedMeasurement[ MAX_TEENSY_SENSOR ]; static CONDUCTIVITY_COEFFICIENTS_T conductivityCoeff[MAX_TEENSY_SENSOR]; static const CONDUCTIVITY_CMD_DATA_T teensyCmdMap[][] = { { TEENSY_CMD_INIT_SENSOR , "a" }, { TEENSY_CMD_GET_INIT_STATUS , "l" }, { TEENSY_CMD_UPDATE_EEPROM_DATA , "save" }, { TEENSY_CMD_GET_EEPROM_DATA , "e" }, { TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS , "cfg" }, { TEENSY_CMD_GET_MEASUREMENT_SETTINGS , "k" }, { TEENSY_CMD_GET_MEASUREMENT , "m" }, { TEENSY_CMD_STOP_MEASUREMENT , "n" }, { TEENSY_CMD_GET_ALL_MEASUREMENTS , "g" }, { TEENSY_CMD_SELECT_SENSOR , "j" }, { TEENSY_CMD_GET_SINGLE_MEASUREMENT , "h" }, }; // Conductivity cmd data structs TEENSY_SENSOR_INDEX_T currentSelectedSensor; CONDUCTIVITY_EEPROM_DATA_T eePromDataTX; CONDUCTIVITY_EEPROM_DATA_T eePromDataRX; CONDUCTIVITY_MEASUREMENT_SETTINGS_T measurementSettingsTX; CONDUCTIVITY_MEASUREMENT_SETTINGS_T measurementSettingsRX; // ********** private function prototypes ********** static void initConductivityDMAchannels( void ); static CONDUCTIVITY_COMM_STATE_T handleConductivityIdle( void ); static CONDUCTIVITY_COMM_STATE_T handleConductivityTX( void ); static CONDUCTIVITY_COMM_STATE_T handleConductivityRX( void ); static void consumeUnexpectedConductivityData( void ); static BOOL isQueueFull ( void ); static BOOL isQueueEmpty ( void ); static BOOL enqueue ( TEENSY_CMD_INDEX_T cmd ); static void dequeue( void ); static void setupConductivityDMAForWriteCmd( U32 bytes2Transmit ); static void startConductivityDMAWriteCmd( void ); static void setupConductivityDMAForWriteResp( U32 bytes2Receive ); static void startConductivityDMAReceiptOfWriteResp( void ); static void setupConductivityDMAForReadCmd( U32 bytes2Transmit ); static void startConductivityDMAReadCmd( void ); static void setupConductivityDMAForReadResp( U32 bytes2Receive ); static void startConductivityDMAReceiptOfReadResp( void ); static CONDUCTIVITY_PARSE_STATUS parseMeasurementSettings(const U32 *buffer, U32 len ); static CONDUCTIVITY_PARSE_STATUS parseEEPROMdata( const U32 *buffer, U32 len ); static CONDUCTIVITY_PARSE_STATUS parseConductivityMeasurements( const U32 *buffer, U32 len ); static BOOL sendTeensyWriteCmd( TEENSY_CMD_INDEX_T cmdIndex, const U08* param ); static BOOL sendTeensyReadCmd( TEENSY_CMD_INDEX_T cmdIndex ); static CONDUCTIVITY_COMM_STATE_T sendCmd_initSensor( void ); static CONDUCTIVITY_COMM_STATE_T sendCmd_getInitStatus( void ); static CONDUCTIVITY_COMM_STATE_T sendCmd_updateEEPROMdata( CONDUCTIVITY_EEPROM_DATA_T eepromData); static CONDUCTIVITY_COMM_STATE_T sendCmd_getEEPROMdata( void ); static CONDUCTIVITY_COMM_STATE_T sendCmd_updateMeasurementSettings( CONDUCTIVITY_MEASUREMENT_SETTINGS_T measurementSettings ); static CONDUCTIVITY_COMM_STATE_T sendCmd_getMeasurementSettings( void ); static CONDUCTIVITY_COMM_STATE_T sendCmd_getMeasurements( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_initSensor( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_getInitStatus( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_updateEEPROMdata( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_updateMeasurementSettings( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_getMeasurementSettings( void ); static CONDUCTIVITY_COMM_STATE_T rcvRspns_getMeasurements( void ); static void sendCmd_stopMeasurement( void ); static void rcvRspns_stopMeasurement( void ); static void sendCmd_getAllMeasurements( void ); static void rcvRspns_getAllMeasurements( void ); static void sendCmd_selectSensor( TEENSY_SENSOR_INDEX_T sensorNum ); static void rcvRspns_selectSensor( TEENSY_SENSOR_INDEX_T sensorNum ); static void sendCmd_getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ); static void rcvRspns_getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ); static CONDUCTIVITY_INIT_STATUS_T getInitStatus( void ); static const CONDUCTIVITY_EEPROM_DATA_T* getEEPROMdata( void ); static const CONDUCTIVITY_MEASUREMENT_SETTINGS_T* getMeasurementSettings( void ); static const CONDUCTIVITY_SENSOR_DATA_T* getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ); static const CONDUCTIVITY_SENSOR_DATA_T* getAllMeasurements( void ); static void calculateConductivity( TEENSY_SENSOR_INDEX_T sensorNum ); static void calculateTemperature( TEENSY_SENSOR_INDEX_T sensorNum ); void initCondTeensy( void ) { conductivityCommState = COND_COMM_STATE_IDLE; condReceiptCounter = 0; condTransmitCounter = 0; // initialize Conductivity comm buffers memset( &condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); memset( &condReadCmdBuffer, 0, COND_READ_CMD_BUFFER_LEN ); initConductivityDMAchannels(); // add init conductivity commands enqueue( TEENSY_CMD_INIT_SENSOR ); enqueue( TEENSY_CMD_GET_MEASUREMENT ); } static void initConductivityDMAchannels( void ) { // 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 // Initialize Conductivity DMA Read Control Record condDMAReadControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) condDMAReadControlRecord.SADD = (U32)condReadCmdBuffer; // Transfer source address condDMAReadControlRecord.DADD = (U32)(&(sciREG->TD)); // Dest. is SCI xmit register condDMAReadControlRecord.CHCTRL = 0; // No chaining condDMAReadControlRecord.ELCNT = 1; // Frame is 1 element condDMAReadControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known condDMAReadControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte condDMAReadControlRecord.WRSIZE = ACCESS_8_BIT; // condDMAReadControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer condDMAReadControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment condDMAReadControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed condDMAReadControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off condDMAReadControlRecord.ELSOFFSET = 0; // Not used condDMAReadControlRecord.ELDOFFSET = 0; // Not used condDMAReadControlRecord.FRSOFFSET = 0; // Not used condDMAReadControlRecord.FRDOFFSET = 0; // Not used // Initialize Conductivity DMA Read Response Control Record condDMAReadRespControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) condDMAReadRespControlRecord.SADD = (U32)(&(sciREG->RD)); // Source is SCI recv register condDMAReadRespControlRecord.DADD = (U32)condReadResponseBuffer; // Transfer destination address condDMAReadRespControlRecord.CHCTRL = 0; // No chaining condDMAReadRespControlRecord.ELCNT = 1; // Frame is 1 element condDMAReadRespControlRecord.FRCNT = 0; // Block is TBD frames - will be populated later when known condDMAReadRespControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte condDMAReadRespControlRecord.WRSIZE = ACCESS_8_BIT; // condDMAReadRespControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer condDMAReadRespControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed condDMAReadRespControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment condDMAReadRespControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off condDMAReadRespControlRecord.ELDOFFSET = 0; // Not used condDMAReadRespControlRecord.ELSOFFSET = 0; // Not used condDMAReadRespControlRecord.FRDOFFSET = 0; // Not used condDMAReadRespControlRecord.FRSOFFSET = 0; // Not used // There should not be any data pending yet consumeUnexpectedConductivityData(); } /*********************************************************************//** * @brief * The execConductivityTeensy function manages incoming data exchanges with * the Teensy board over UART. * @details \b Inputs: conductivityCommState * @details \b Outputs: conductivityCommState * @return none *************************************************************************/ void execConductivityTeensy( void ) { switch ( conductivityCommState ) { case COND_COMM_STATE_IDLE: conductivityCommState = handleConductivityIdle(); break; case COND_COMM_STATE_SEND_CMD: conductivityCommState = handleConductivityTX(); break; case COND_COMM_STATE_RCV_RSPNS: conductivityCommState = handleConductivityRX(); break; default: SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, (U32)conductivityCommState ) break; } } /*********************************************************************//** * @brief * The handleConductivityIdle handles the command queue and transitions to the respective * comm state. * @details \b Inputs: TBD * @details \b Outputs: TBD * @return none *************************************************************************/ static CONDUCTIVITY_COMM_STATE_T handleConductivityIdle( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_IDLE; if ( !isQueueEmpty() ) { dequeue(); state = COND_COMM_STATE_SEND_CMD; } return state; } /*********************************************************************//** * @brief * The handleConductivityTX handles the transmission of data over UART * to the Teensy board. * @details \b Inputs: TBD * @details \b Outputs: TBD * @return none *************************************************************************/ static CONDUCTIVITY_COMM_STATE_T handleConductivityTX( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD; switch ( currentCmd ) { case TEENSY_CMD_INIT_SENSOR: state = sendCmd_initSensor(); break; case TEENSY_CMD_GET_INIT_STATUS: state = sendCmd_getInitStatus(); break; case TEENSY_CMD_UPDATE_EEPROM_DATA: state = sendCmd_updateEEPROMdata( eePromDataTX ); break; case TEENSY_CMD_GET_EEPROM_DATA: state = sendCmd_getEEPROMdata(); break; case TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS: state = sendCmd_updateMeasurementSettings( measurementSettingsTX ); break; case TEENSY_CMD_GET_MEASUREMENT_SETTINGS: state = sendCmd_getMeasurementSettings(); break; case TEENSY_CMD_GET_MEASUREMENT: state = sendCmd_getMeasurements(); break; case TEENSY_CMD_STOP_MEASUREMENT: sendCmd_stopMeasurement(); break; case TEENSY_CMD_GET_ALL_MEASUREMENTS: sendCmd_getAllMeasurements(); break; case TEENSY_CMD_SELECT_SENSOR: sendCmd_selectSensor( currentSelectedSensor ); break; case TEENSY_CMD_GET_SINGLE_MEASUREMENT: sendCmd_getSingleMeasurement( currentCmd ); break; default: break; } return state; } /*********************************************************************//** * @brief * The handleConductivityRX handles the receiving of data over UART * to the Teensy board. * @details \b Inputs: TBD * @details \b Outputs: TBD * @return none *************************************************************************/ static CONDUCTIVITY_COMM_STATE_T handleConductivityRX( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD; 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_GET_MEASUREMENT: break; case TEENSY_CMD_STOP_MEASUREMENT: break; case TEENSY_CMD_GET_ALL_MEASUREMENTS: break; case TEENSY_CMD_SELECT_SENSOR: break; case TEENSY_CMD_GET_SINGLE_MEASUREMENT: break; default: break; } return state; } /*********************************************************************//** * @brief * The signalConductivityReceiptCompleted function increments a counter to indicate * that another DMA receipt from the Conductivity has completed and sets comm flags * indicating pending response from Conductivity is completed. * @details \b Inputs: none * @details \b Outputs: condReceiptCounter, condWriteCommandInProgress, * condWriteCmdRspnsRcvd, condReadCommandInProgress, * condReadCmdRspnsRcvd, condBulkWriteAndReadInProgress * @return none *************************************************************************/ void signalConductivityReceiptCompleted( void ) { condReceiptCounter++; // Did Conductivity Ack last command? if ( TRUE == condWriteCommandInProgress ) { condWriteCommandInProgress = FALSE; condWriteCmdRspnsRcvd = TRUE; } else if ( TRUE == condReadCommandInProgress ) { condReadCommandInProgress = FALSE; condReadCmdRspnsRcvd = TRUE; } // See if we want to follow up with a bulk read command if ( TRUE == condBulkWriteAndReadInProgress ) { condBulkWriteAndReadInProgress = FALSE; condReadCommandInProgress = TRUE; // Initiate bulk read command startConductivityDMAReceiptOfReadResp(); startConductivityDMAReadCmd(); } } /*********************************************************************//** * @brief * The signalConductivityTransmitCompleted function increments a counter to indicate * that another DMA transmit to the Conductivity has completed. * @details \b Inputs: none * @details \b Outputs: condTransmitCounter * @return none *************************************************************************/ void signalConductivityTransmitCompleted( void ) { condTransmitCounter++; } /*********************************************************************//** * @brief * The getImpedanceValue function gets the current calculated conductivity / impedance value. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if given sensor is invalid. * @details \b Inputs: lastConductivityErrorCounter * @details \b Outputs: none * @param sensor ID of conductivity sensor to get error count for. * @return The current conductivity sensor error count of a given conductivity sensor. *************************************************************************/ F64 getImpedanceValue( U32 sensorNum ) { return calculatedMeasurement[sensorNum].Conductivity; } /*********************************************************************//** * @brief * The getRTDValue function gets the current conductivity sensor * error count for a given conductivity sensor. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if given sensor is invalid. * @details \b Inputs: lastConductivityErrorCounter * @details \b Outputs: none * @param sensor ID of conductivity sensor to get error count for. * @return The current conductivity sensor error count of a given conductivity sensor. *************************************************************************/ F64 getRTDValue( U32 sensorNum ) { return calculatedMeasurement[sensorNum].Temperature; } /*********************************************************************//** * @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 is queue is full *************************************************************************/ 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 false. * @details Inputs: queueCount * @details Outputs: none * @return TRUE if queue is not empty *************************************************************************/ static BOOL isQueueEmpty ( void ) { BOOL isEmpty = TRUE; if ( queueCount > 0 ) { isEmpty = FALSE; } return isEmpty; } /*********************************************************************//** * @brief * The dequeue 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 ( !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 job from the job 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 ( !isQueueEmpty() ) { queueFrontIndex = INC_WRAP( queueFrontIndex, 0, COND_CMD_Q_LEN - 1 ); currentCmd = condCmdQ [ tempIndex ]; } if ( queueCount > 0 ) { queueCount--; } _enable_IRQ(); } static void consumeUnexpectedConductivityData( void ) { // Clear any errors sciRxError( sciREG ); // If a byte is pending read, read it if ( sciIsRxReady( sciREG ) != 0 ) { sciReceiveByte( sciREG ); } } static void setupConductivityDMAForWriteCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= COND_WRITE_CMD_BUFFER_LEN ) { condDMAWriteControlRecord.FRCNT = bytes2Transmit; } } static void startConductivityDMAWriteCmd( void ) { dmaSetCtrlPacket( DMA_CH3, condDMAWriteControlRecord ); dmaSetChEnable( DMA_CH3, DMA_HW ); setSCIDMATransmitInterrupt(); } static void setupConductivityDMAForWriteResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= COND_WRITE_RSP_BUFFER_LEN ) { condDMAWriteRespControlRecord.FRCNT = bytes2Receive; } } static void startConductivityDMAReceiptOfWriteResp( void ) { dmaSetCtrlPacket( DMA_CH1, condDMAWriteRespControlRecord ); dmaSetChEnable( DMA_CH1, DMA_HW ); setSCIDMAReceiveInterrupt(); } static void setupConductivityDMAForReadCmd( U32 bytes2Transmit ) { // Verify # of bytes does not exceed buffer length if ( bytes2Transmit <= COND_READ_CMD_BUFFER_LEN ) { condDMAReadControlRecord.FRCNT = bytes2Transmit; } } static void startConductivityDMAReadCmd( void ) { dmaSetCtrlPacket( DMA_CH3, condDMAReadControlRecord ); dmaSetChEnable( DMA_CH3, DMA_HW ); setSCIDMATransmitInterrupt(); } static void setupConductivityDMAForReadResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length if ( bytes2Receive <= COND_READ_RSP_BUFFER_LEN ) { condDMAReadRespControlRecord.FRCNT = bytes2Receive; } } static void startConductivityDMAReceiptOfReadResp( void ) { dmaSetCtrlPacket( DMA_CH1, condDMAReadRespControlRecord ); dmaSetChEnable( DMA_CH1, DMA_HW ); setSCIDMAReceiveInterrupt(); } /*********************************************************************//** * @brief * The parseMeasurementSettings Reads measurement settings from buffer and * stores in conductivityMeasurementSettings. * @details \b Inputs : none * @details \b Outputs: conductivityMeasurementSettings - Measurement Settings * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return CONDUCTIVITY_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static CONDUCTIVITY_PARSE_STATUS parseMeasurementSettings( const U32 *buffer, U32 len ) { CONDUCTIVITY_PARSE_STATUS parseStatus = CONDUCTIVITY_PARSE_SUCCESS; U32 expectedDataLength = sizeof( CONDUCTIVITY_MEASUREMENT_SETTINGS_T ); // Validate buffer if ( buffer == NULL ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_NULL_BUFFER; } // Validate buffer length else if ( len != expectedDataLength ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_INVALID_LENGTH; } else { // Parse and Store the data memcpy( &conductivityMeasurementSettings, buffer, expectedDataLength ); } return parseStatus; } /*********************************************************************//** * @brief * The parseEEPROMdata Reads EEPROM data from buffer and * stores in conductivityEEPROMdata. * @details \b Inputs : none * @details \b Outputs: conductivityEEPROMdata - EEPROM data * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return CONDUCTIVITY_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static CONDUCTIVITY_PARSE_STATUS parseEEPROMdata( const U32 *buffer, U32 len ) { CONDUCTIVITY_PARSE_STATUS parseStatus = CONDUCTIVITY_PARSE_SUCCESS; U32 expectedDataLength = sizeof( CONDUCTIVITY_EEPROM_DATA_T ); // Validate buffer if ( buffer == NULL ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_NULL_BUFFER; } // Validate buffer length else if ( len != expectedDataLength ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_INVALID_LENGTH; } else { // Parse and Store the data memcpy( &conductivityEEPROMdata, buffer, expectedDataLength ); } return parseStatus; } /*********************************************************************//** * @brief * The parseConductivityMeasurements Reads Conductivity Measurements / Sensor readings * from buffer and stores in rawConductivityValues. * @details \b Inputs : none * @details \b Outputs: rawConductivityValues - Raw Conductivity Measurements / Sensor readings * @param buffer - Data to be parsed and stored. * len - Length of the input data. * @return CONDUCTIVITY_PARSE_STATUS to tell if parsing was successful or not. *************************************************************************/ static CONDUCTIVITY_PARSE_STATUS parseConductivityMeasurements( const U32 *buffer, U32 len ) { CONDUCTIVITY_PARSE_STATUS parseStatus = CONDUCTIVITY_PARSE_SUCCESS; U32 expectedDataLength = sizeof( CONDUCTIVITY_SENSOR_DATA_T ); U32 sensorCount = 0; U16 sensorIdx = 0; // // Validate buffer if ( NULL == buffer ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_NULL_BUFFER; } // Validate buffer length else if ( ( len % expectedDataLength ) != 0 ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_INVALID_LENGTH; } else { // Calculate the number of sensors for which we have received the data sensorCount = len / expectedDataLength; // Parse the data and store in conductivityMeasurements[] for ( sensorIdx = 0; sensorIdx < sensorCount; sensorIdx++ ) { // Read the sensor data temporarily CONDUCTIVITY_SENSOR_DATA_T tempSensor; memcpy(&tempSensor, ( buffer + ( sensorIdx * expectedDataLength ) ), expectedDataLength ); // And check if the received sensor number id valid if ( (tempSensor.sensorNum < 1 ) || ( tempSensor.sensorNum > MAX_TEENSY_SENSOR ) ) { parseStatus = CONDUCTIVITY_PARSE_ERROR_INVALID_SENSOR_NUM; break; } else { // The received data value contains sensor values from 1 to 6. // So store value in array index for position (sensorNum - 1) i.e. 0 to 5. rawConductivityValues[tempSensor.sensorNum - 1] = tempSensor; } } } return parseStatus; } /** * @brief Writes a command (with optional parameters) to the write buffer. * * @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 sendTeensyWriteCmd( TEENSY_CMD_INDEX_T cmdIndex, const U08* param ) { BOOL success = FALSE; U32 txByteLength = 0; // Validate command index and ensure command string exists if ( ( cmdIndex >= MAX_NUM_OF_TEENSY_CMDS ) || ( NULL == teensyCmdMap[ cmdIndex ][ 1 ] ) ) { success = FALSE; } else { const U08* baseCmd = (const U08*)teensyCmdMap[ cmdIndex ]; // Clear the write buffer before writing memset( condWriteCmdBuffer, 0, COND_WRITE_CMD_BUFFER_LEN ); // Format command with optional parameter if ( ( NULL != param ) && ( strlen( (const char*)param ) > 0 ) ) { written = snprintf( (char*)condWriteCmdBuffer, COND_WRITE_CMD_BUFFER_LEN, "%s %s", (const char*)baseCmd, (const char*)param ); if ( written > 0 ) { success = TRUE; } } else { written = snprintf( (char*)condWriteCmdBuffer, COND_WRITE_CMD_BUFFER_LEN, "%s", (const char*)baseCmd ); if ( written > 0 ) { success = TRUE; } } } condWriteCommandInProgress = TRUE; setupConductivityDMAForWriteCmd( written ); startConductivityDMAWriteCmd(); return success; } /** * @brief Writes a command (without parameters) to the read buffer. * * @param cmdIndex Index of the command in teensyCmd[]. * @return TRUE if the command was successfully written to the read buffer, FALSE otherwise. */ static BOOL sendTeensyReadCmd( TEENSY_CMD_INDEX_T cmdIndex ) { BOOL success = FALSE; // Validate command index and ensure command string exists if ( ( cmdIndex >= MAX_NUM_OF_TEENSY_CMDS ) || ( NULL == teensyCmd[ cmdIndex ] ) ) { success = FALSE; } else { const U08* baseCmd = (const U08*)teensyCmd[ cmdIndex ]; // Clear the read buffer before writing memset( condReadCmdBuffer, 0, COND_READ_CMD_BUFFER_LEN ); // Write only the command string (no parameters allowed) U16 written = snprintf( (char*)condReadCmdBuffer, COND_READ_CMD_BUFFER_LEN, "%s", (const char*)baseCmd ); success = ( written > 0 ) && ( written < COND_READ_CMD_BUFFER_LEN ); } return success; } static CONDUCTIVITY_COMM_STATE_T sendCmd_initSensor( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD; if ( FALSE == sendTeensyWriteCmd( TEENSY_CMD_INIT_SENSOR, NULL ) ) { // Handle error: log or set error flag } else { // Waiting for DMA Read buffer true state = COND_COMM_STATE_RCV_RSPNS; } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_initSensor( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_INIT_SENSOR; // condWriteResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_getInitStatus( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_GET_INIT_STATUS; if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_INIT_STATUS ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_getInitStatus( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_GET_INIT_STATUS; // condReadResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_updateEEPROMdata( CONDUCTIVITY_EEPROM_DATA_T eepromData ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_UPDATE_EEPROM_DATA; // Format EEPROM data into a string U08 paramStr[256]; U16 offset = 0; U16 i = 0; for ( i = 0; i < DOUBLE_COUNT; ++i ) { offset += snprintf( (char*)(paramStr + offset), sizeof(paramStr) - offset, "%.6f,", eepromData.doubleValue[i] ); } for ( i = 0; i < FLOAT_COUNT; ++i ) { offset += snprintf( (char*)(paramStr + offset), sizeof(paramStr) - offset, "%.6f,", eepromData.floatValue[i] ); } // Remove trailing comma if needed if ( ( offset > 0 ) && ( paramStr[ offset - 1 ] == ',' ) ) { paramStr[ offset - 1 ] = '\0'; } if ( FALSE == sendTeensyWriteCmd( TEENSY_CMD_UPDATE_EEPROM_DATA, paramStr ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_updateEEPROMdata( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_UPDATE_EEPROM_DATA; // condWriteResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_getEEPROMdata( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_GET_EEPROM_DATA; if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_EEPROM_DATA ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_getEEPROMdata( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_GET_EEPROM_DATA; // condReadResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_updateMeasurementSettings( CONDUCTIVITY_MEASUREMENT_SETTINGS_T measurementSettings ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_UPDATE_MEASUREMENT_SETTINGS; // Format measurement settings into a string U08 paramStr[128]; snprintf( (char*)paramStr, sizeof(paramStr), "%.3f,%.3f,%.3f,%u,%u,%u,%u", measurementSettings.SinFreq, measurementSettings.DacVoltPP, measurementSettings.BiasVolt, measurementSettings.HstiaRtiaSel, measurementSettings.AdcPgaGain, measurementSettings.DftNum, measurementSettings.ADCAvgNum ); if ( FALSE == sendTeensyWriteCmd( TEENSY_CMD_UPDATE_MEASUREMENT_SETTINGS, paramStr ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_updateMeasurementSettings( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_UPDATE_MEASUREMENT_SETTINGS; // condWriteResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_getMeasurementSettings( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_GET_MEASUREMENT_SETTINGS; if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_MEASUREMENT_SETTINGS ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_getMeasurementSettings( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_GET_MEASUREMENT_SETTINGS; // condReadResponseBuffer return state; } static CONDUCTIVITY_COMM_STATE_T sendCmd_getMeasurements( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_SEND_CMD_GET_MEASUREMENT; if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_MEASUREMENT ) ) { // Handle error } return state; } static CONDUCTIVITY_COMM_STATE_T rcvRspns_getMeasurements( void ) { CONDUCTIVITY_COMM_STATE_T state = COND_COMM_STATE_RCV_RSPNS_GET_MEASUREMENT; // condReadResponseBuffer return state; } static void sendCmd_stopMeasurement( void ) { if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_STOP_MEASUREMENT ) ) { // Handle error } } static void rcvRspns_stopMeasurement( void ) { // condReadResponseBuffer } static void sendCmd_getAllMeasurements( void ) { if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_ALL_MEASUREMENTS ) ) { // Handle error } } static void rcvRspns_getAllMeasurements( void ) { // condReadResponseBuffer } static void sendCmd_selectSensor( TEENSY_SENSOR_INDEX_T sensorNum ) { U08 paramStr[8]; snprintf( (char*)paramStr, sizeof(paramStr), "%d", sensorNum ); if ( FALSE == sendTeensyWriteCmd( TEENSY_CMD_SELECT_SENSOR, paramStr ) ) { // Handle error } } static void rcvRspns_selectSensor( TEENSY_SENSOR_INDEX_T sensorNum ) { // condWriteResponseBuffer } static void sendCmd_getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ) { // Assumes sensor has already been selected if ( FALSE == sendTeensyReadCmd( TEENSY_CMD_GET_SINGLE_MEASUREMENT ) ) { // Handle error } } static void rcvRspns_getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ) { // condReadResponseBuffer } static CONDUCTIVITY_INIT_STATUS_T getInitStatus( void ) { sendCmd_getInitStatus(); rcvRspns_getInitStatus(); return conductivityInitStatus; } static const CONDUCTIVITY_EEPROM_DATA_T* getEEPROMdata(void) { return &conductivityEEPROMdata; } static const CONDUCTIVITY_MEASUREMENT_SETTINGS_T* getMeasurementSettings(void) { return &conductivityMeasurementSettings; } static const CONDUCTIVITY_SENSOR_DATA_T* getSingleMeasurement( TEENSY_SENSOR_INDEX_T sensorNum ) { const CONDUCTIVITY_SENSOR_DATA_T* result = NULL; if (sensorNum < MAX_TEENSY_SENSOR) { result = &rawConductivityValues[ sensorNum ]; } return result; } static const CONDUCTIVITY_SENSOR_DATA_T* getAllMeasurements( void ) { return rawConductivityValues; } static void calculateConductivity( TEENSY_SENSOR_INDEX_T sensorNum ) { F64 calculatedConductivity = 0.0; F64 B3 = conductivityCoeff[ sensorNum ].B3; F64 B2 = conductivityCoeff[ sensorNum ].B2; F64 B1 = conductivityCoeff[ sensorNum ].B1; F64 B0 = conductivityCoeff[ sensorNum ].B0; F64 R = rawConductivityValues[ sensorNum ].impRzMag; F64 Z = rawConductivityValues[ sensorNum ].rtdRzMag; calculatedConductivity = ( ( B3 * ( 1000.0 / R ) ) + ( B2 * ( Z / R ) ) + ( B1 * ( ( 100 * log( Z ) ) / R ) ) + B0 ); calculatedMeasurement[sensorNum].Conductivity = calculatedConductivity; } static void calculateTemperature( TEENSY_SENSOR_INDEX_T sensorNum ) { F64 calculatedTemperature = 0.0; F64 A1 = conductivityCoeff[ sensorNum ].A1; F64 A0 = conductivityCoeff[ sensorNum ].A0; F64 Z = rawConductivityValues[ sensorNum ].rtdRzMag; calculatedTemperature = ( ( A1 * Z ) + A0 ); calculatedMeasurement[sensorNum].Temperature = calculatedTemperature; }