/************************************************************************** * * Copyright (c) 2024-2024 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 Messaging.c * * @author (last) Vinayakam Mani * @date (last) 06-Aug-2024 * * @author (original) Vinayakam Mani * @date (original) 06-Aug-2024 * ***************************************************************************/ #include // for memcpy() #include "reg_system.h" #include "BalancingChamber.h" #include "BloodLeak.h" #include "BoostPump.h" #include "Conductivity.h" #include "Compatible.h" #include "ConcentratePumps.h" #include "DialysatePumps.h" #include "Flow.h" #include "FlowSensor.h" #include "FluidPump.h" #include "FlushConcentrate.h" #include "FlushFilter.h" #include "FlushPermeate.h" #include "FpgaDD.h" #include "FPModeFault.h" #include "FPModeInitPOST.h" #include "FPModeStandby.h" #include "FPOperationModes.h" #include "Heaters.h" #include "InletPressureCheck.h" #include "Level.h" #include "Messaging.h" #include "MessagePayloads.h" #include "ModeGenDialysate.h" #include "ModeGenPermeate.h" #include "ModePreGenDialysate.h" #include "ModePreGenPermeate.h" #include "ModePostGenDialysate.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PAL.h" #include "PermeateTank.h" #include "Pressure.h" #include "RinsePump.h" #include "ROPump.h" #include "SafetyShutdown.h" #include "SpentChamberFill.h" #include "SystemCommDD.h" #include "Temperature.h" #include "TestSupport.h" #include "TDInterface.h" #include "Utilities.h" #include "Ultrafiltration.h" #include "Valves.h" #include "Voltages.h" /** * @addtogroup Messaging * @{ */ // ********** private definitions ********** #define MAX_MSGS_BLOCKED_FOR_XMIT 8 ///< Maximum number of messages to block transmission for. #pragma pack(push,1) /// Payload record structure for block message transmission request. typedef struct { U16 blockedMessages[ MAX_MSGS_BLOCKED_FOR_XMIT ]; ///< Blocked messages array. } BLOCKED_MSGS_DATA_T; #pragma pack(pop) /// Array of CAN communication buffers to respond on (aligned with enum Comm_Buffers). static const COMM_BUFFER_T tdResponseBuffers[ NUM_OF_COMM_BUFFERS ] = { COMM_BUFFER_NOT_USED, ///< CAN message boxes start at 1 so we will not use this buffer COMM_BUFFER_OUT_CAN_DD_ALARM, ///< Buffer for responding to incoming TD alarm messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing DD alarm messages so no response buffer COMM_BUFFER_NOT_USED, ///< Buffer for outgoing FP alarm messages so no response buffer COMM_BUFFER_OUT_CAN_DD_ALARM, ///< Buffer for responding to incoming UI alarm messages COMM_BUFFER_OUT_CAN_DD_2_TD, ///< Buffer for responding to incoming TD to DD messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing DD to TD messages so no response buffer COMM_BUFFER_OUT_CAN_DD_BROADCAST, ///< Buffer for responding to incoming TD broadcast messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing DD broadcast messages so no response buffer COMM_BUFFER_NOT_USED, ///< Buffer for outgoing FP broadcast messages so no response buffer COMM_BUFFER_OUT_CAN_DD_BROADCAST, ///< Buffer for responding to incoming UI broadcast messages COMM_BUFFER_OUT_DD_CAN_PC, ///< Buffer for responding to incoming PC to DD messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing DD to PC messages so no response buffer COMM_BUFFER_OUT_FP_CAN_PC, ///< Buffer for responding to incoming PC to FP messages COMM_BUFFER_NOT_USED, ///< Buffer for outgoing FP to PC messages so no response buffer }; typedef BOOL (*MsgFuncPtr)( MESSAGE_T* ); /// Message handling look-up table record type. typedef struct { U16 msgID; ///< ID of received message to handle. MsgFuncPtr msgHandler; ///< Pointer to message handling function associated with a message ID. } MSG_HANDLER_LOOKUP_T; /// Message handling function lookup table static const MSG_HANDLER_LOOKUP_T MSG_FUNCTION_HANDLER_LOOKUP[] = { { MSG_ID_DD_TESTER_LOGIN_REQUEST, &handleTesterLogInRequest }, { MSG_ID_DD_SOFTWARE_RESET_REQUEST, &handleDDSoftwareResetRequest }, { MSG_ID_TD_OP_MODE_DATA, &handleSetTDOperationMode }, { MSG_ID_DD_VALVE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testValvesStatesPublishIntervalOverride }, { MSG_ID_DD_VALVE_STATE_OVERRIDE_REQUEST, &testValveStateOverride }, { MSG_ID_DD_VALVE_SENSED_STATE_OVERRIDE_REQUEST, &testValveSensedStateOverride }, { MSG_ID_DD_PRESSURE_SENSOR_READINGS_OVERRIDE_REQUEST, &testDDPressureSensorReadingsOverride }, { MSG_ID_DD_PRESSURE_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testDDPressureSensorTemperatureReadingsOverride }, { MSG_ID_DD_PRESSURE_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDPressureSensorDataPublishIntervalOverride }, { MSG_ID_DD_PRESSURE_SENSOR_FILTER_READINGS_OVERRIDE_REQUEST, &testDDPressureSensorFilteredReadingsOverride }, { MSG_ID_DD_PRESSURE_SENSOR_FILTER_TEMPERATURE_OVERRIDE_REQUEST, &testDDPressureSensorFilteredTemperatureReadingsOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_READINGS_OVERRIDE_REQUEST, &testDDConductivitySensorReadingsOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testDDConductivitySensorTemperatureReadingsOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_READ_COUNTER_OVERRIDE_REQUEST, &testDDConductivitySensorReadCounterOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_ERROR_COUNTER_OVERRIDE_REQUEST, &testDDConductivitySensorErrorCounterOverride }, { MSG_ID_DD_CONDUCTIVITY_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDConductivitySensorDataPublishIntervalOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testConcentratePumpDataPublishIntervalOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_TARGET_SPEED_OVERRIDE_REQUEST, &testConcentratePumpTargetSpeedOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_MEASURED_SPEED_OVERRIDE_REQUEST, &testConcentratePumpMeasuredSpeedOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_PARKED_OVERRIDE_REQUEST, &testConcentratePumpParkedOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_PARK_FAULT_OVERRIDE_REQUEST, &testConcentratePumpParkCmdFaultedOverride }, { MSG_ID_DD_CONCENTRATE_PUMP_PARK_REQUEST_OVERRIDE_REQUEST, &testConcentratePumpParkRequestOverride }, { MSG_ID_DD_TEMPERATURE_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDDTemperatureSensorsDataPublishIntervalOverride }, { MSG_ID_DD_TEMPERATURE_SENSOR_MEASURED_TEMPERATURE_OVERRIDE_REQUEST, &testMeasuredTemperatureOverride }, { MSG_ID_DD_TEMPERATURE_SENSOR_READ_COUNTER_OVERRIDE_REQUEST, &testTemperatureReadCounterOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testDialysatePumpsDataPublishIntervalOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_TARGET_SPEED_OVERRIDE_REQUEST, &testDialysatePumpTargetSpeedOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_MEASURED_SPEED_OVERRIDE_REQUEST, &testDialysatePumpMeasuredSpeedOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_TARGET_PRESSURE_OVERRIDE_REQUEST, &testDialysatePumpTargetPressureOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_MEASURED_CURRENT_OVERRIDE_REQUEST, &testDialysatePumpMeasuredCurrentOverride }, { MSG_ID_DD_DIALYSATE_PUMPS_MEASURED_DIRECTION_OVERRIDE_REQUEST, &testDialysatePumpMeasuredDirectionOverride }, { MSG_ID_DD_HEATERS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testHeatersDataPublishIntervalOverride }, { MSG_ID_DD_HEATERS_DUTY_CYCLE_OVERRIDE_REQUEST, &testHeaterDutyCycleOverride }, { MSG_ID_DD_LEVELS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testLevelsDataPublishIntervalOverride }, { MSG_ID_DD_LEVELS_STATUS_OVERRIDE_REQUEST, &testLevelStatusOverride }, { MSD_ID_DD_TD_COMMUNICATION_STATUS_OVERRIDE_REQUEST, &testTDCommunicationStatusOverride }, { MSG_ID_DD_OP_MODE_STATUS_OVERRIDE_REQUEST, &testDDOpModePublishIntervalOverride }, { MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST, &testSetOperationMode }, { MSG_ID_DD_DIALYSATE_PUMPS_START_STOP_OVERRIDE_REQUEST, &testDialysatePumpStartStopOverride }, { MSG_ID_DD_GEND_MODE_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDGenDialysateDataPublishIntervalOverride }, { MSG_ID_DD_CONCENTRATE_PUMPS_START_STOP_OVERRIDE_REQUEST, &testConcentratePumpStartStopOverride }, { MSG_ID_DD_HEATERS_START_STOP_OVERRIDE_REQUEST, &testHeaterStartStopOverride }, { MSG_ID_DD_VALVES_OPEN_CLOSE_STATE_OVERRIDE_REQUEST, &testValveOpenCloseStateOverride }, { MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA, &handleDialysateDeliveryRequestMsg }, { MSD_ID_DD_FP_COMMUNICATION_STATUS_OVERRIDE_REQUEST, &testFPCommunicationStatusOverride }, { MSG_ID_DD_BAL_CHAMBER_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDBalChamberDataPublishIntervalOverride }, { MSG_ID_DD_BAL_CHAMBER_SWITCH_FREQ_OVERRIDE_REQUEST, &testBalChamberSwFreqOverride }, { MSG_ID_DD_DIAL_DELIVERY_IN_PROGRESS_OVERRIDE_REQUEST, &testDialDeliveryInProgressOverride }, { MSG_ID_DD_DIAL_DELIVERY_GOOD_TO_DELIVER_OVERRIDE_REQUEST, &testDialGoodToDeliverStatusOverride }, { MSG_ID_DD_HEATERS_TARGET_TEMPERATURE_OVERRIDE_REQUEST, &testHeaterTargetTemperatureOverride }, { MSG_ID_DD_BC_VALVE_STATES_OVERRIDE_REQUEST, &testBCValveStatesOverride }, { MSG_ID_DD_BC_SWITCH_ONLY_START_STOP_OVERRIDE_REQUEST, &testBCSwitchOnlyStartStopOverride }, { MSG_ID_DD_HYD_CHAMBER_TARGET_TEMP_OVERRIDE_REQUEST, &testGenDHydChamberFluidTempOverride }, { MSG_ID_DD_ACID_DOSING_VOLUME_OVERRIDE_REQUEST, &testAcidDoseVolumeOverride }, { MSG_ID_DD_BICARB_DOSING_VOLUME_OVERRIDE_REQUEST, &testBicarbDoseVolumeOverride }, { MSG_ID_DD_GEND_EXEC_STATE_OVERRIDE_REQUEST, &testGenDExecStateOverride }, { MSG_ID_DD_HEATERS_PWM_PERIOD_OVERIDE_REQUEST, &testHeaterPWMPeriodOverride }, { MSG_ID_DD_PRE_GEND_MODE_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDPreGenDialysateDataPublishIntervalOverride }, { MSG_ID_DD_POST_GEND_MODE_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDPostGenDialysateDataPublishIntervalOverride }, { MSG_ID_DD_PRE_GEN_DIALYSATE_REQUEST_DATA, &handlePreGenDialysateRequestMsg }, { MSG_ID_FW_VERSIONS_REQUEST, &handleVersionRequestMessage }, { MSG_ID_DD_SAFETY_SHUTDOWN_OVERRIDE_REQUEST, &testSetResetSafetyShutdownOverride }, { MSG_ID_DD_UF_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDUFDataPublishIntervalOverride }, { MSG_ID_DD_SET_TEST_CONFIGURATION, &testSetTestConfiguration }, { MSG_ID_DD_GET_TEST_CONFIGURATION, &testGetTestConfiguration }, { MSG_ID_DD_RESET_ALL_TEST_CONFIGURATIONS, &testResetAllTestConfigurations }, { MSG_ID_DD_SPENT_CHAMB_FILL_DATA_PUBLISH_OVERRIDE_REQUEST, &testDDSpentChamberFillDataPublishIntervalOverride }, { MSG_ID_DD_BLOOD_LEAK_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBloodLeakDataPublishIntervalOverride }, { MSG_ID_DD_BLOOD_LEAK_STATUS_OVERRIDE_REQUEST, &testBloodLeakStatusOverride }, { MSG_ID_DD_BLOOD_LEAK_SET_TO_EMBEDDED_MODE_REQUEST, &testSetBloodLeak2EmbeddedMode }, { MSG_ID_DD_BLOOD_LEAK_SET_EMBEDDED_MODE_CMD_REQUEST, &testSetBloodLeakEmbeddedModeCommand }, { MSG_ID_DD_BLOOD_LEAK_EMBEDDED_MODE_INFO_OVERRIDE_REQUEST, &testBloodLeakEmbeddedModeInfoOverride }, { MSG_ID_DD_BLOOD_LEAK_INTENSITY_MOVING_AVERAGE_OVERRIDE_REQUEST, &testBloodLeakIntensityMovingAverageOverride }, { MSG_ID_DD_BLOOD_LEAK_ZEROING_INTERVAL_IN_MS_OVERRIDE_REQUEST, &testBloodLeakZeroingIntervalInMillisecondsOverride }, { MSG_ID_DD_BLOOD_LEAK_ZERO_REQUEST, &testBloodLeakZeroSequenceRequest }, { MSG_ID_DD_FILTERED_COND_SENSOR_READINGS_OVERRIDE_REQUEST, &testDDConductivitySensorFilteredReadingsOverride }, { MSG_ID_DD_FILTERED_COND_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testDDConductivitySensorFilteredTemperatureReadingsOverride }, { MSG_ID_FP_TESTER_LOGIN_REQUEST, &handleTesterFPLogInRequest }, { MSG_ID_FP_SET_OPERATION_MODE_REQUEST, &testSetFPOperationMode }, { MSG_ID_FP_OPERATION_MODE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testSetFPOpModePublishIntervalOverride }, { MSG_ID_FP_PRE_GEN_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testPreGenDataPublishIntervalOverride }, { MSG_ID_FP_INLET_PRES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testInletPressureCheckDataPublishIntervalOverride }, { MSG_ID_FP_INLET_PRES_CHECK_TIME_OVERRIDE_REQUEST, &testInletPressureCheckTimerOverride }, { MSG_ID_FP_BOOST_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testBoostPumpDataPublishIntervalOverride }, { MSG_ID_FP_BOOST_PUMP_TARGET_PRESSURE_OVERRIDE_REQUEST, &testBoostPumpTargetPressureOverride }, { MSG_ID_FP_BOOST_PUMP_TARGET_FLOW_OVERRIDE_REQUEST, &testBoostPumpTargetFlowOverride }, { MSG_ID_FP_BOOST_PUMP_TARGET_PWM_OVERRIDE_REQUEST, &testBoostPumpTargetDutyCycleOverride }, { MSG_ID_FP_BOOST_PUMP_STOP_REQUEST, &testBoostPumpHardStop }, { MSG_ID_FP_FLUID_PUMP_SET_PWM_REQUEST, &testSetFluidPumpPWM }, { MSG_ID_FP_FLUID_PUMP_READ_PWM_OVERRIDE_REQUEST, &testFluidPumpPWMOverride }, { MSG_ID_FP_FLUID_PUMP_SPEED_OVERRIDE_REQUEST, &testFluidPumpRPMOverride }, { MSG_ID_FP_RO_PUMP_STOP_REQUEST, &testROPumpHardStop }, { MSG_ID_FP_RO_PUMP_TARGET_PRESSURE_OVERRIDE_REQUEST, &testROPumpTargetPressureOverride }, { MSG_ID_FP_RO_PUMP_TARGET_FLOW_OVERRIDE_REQUEST, &testROPumpTargetFlowOverride }, { MSG_ID_FP_RO_PUMP_TARGET_PWM_OVERRIDE_REQUEST, &testROPumpTargetDutyCycleOverride }, { MSG_ID_FP_PRESSURE_OVERRIDE_REQUEST, &testIOFPPressureSensorReadingsOverride }, { MSG_ID_FP_PRESSURE_TEMP_OVERRIDE_REQUEST, &testIOFPPressureSensorTemperatureReadingsOverride }, { MSG_ID_FP_PRESSURE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testIOFPPressureSensorDataPublishIntervalOverride }, { MSG_ID_FP_PRESSURE_SENSOR_FILTER_READINGS_OVERRIDE_REQUEST, &testIOFPPressureSensorFilteredReadingsOverride }, { MSG_ID_FP_PRESSURE_SENSOR_FILTER_TEMPERATURE_OVERRIDE_REQUEST, &testIOFPPressureSensorFilteredTemperatureReadingsOverride }, { MSG_ID_FP_TEMPERATURE_SENSOR_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testIOFPTemperatureSensorsDataPublishIntervalOverride }, { MSG_ID_FP_VALVE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testIOFPValvesStatesPublishIntervalOverride }, { MSG_ID_FP_VALVE_CMD_STATE_OVERRIDE_REQUEST, &testIOFPValveStateOverride }, { MSG_ID_FP_VALVE_SENSED_STATE_OVERRIDE_REQUEST, &testIOFPValveSensedStateOverride }, { MSG_ID_FP_FLOWS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testFlowSensorDataPublishIntervalOverride }, { MSG_ID_FP_FLOW_RATE_OVERRIDE_REQUEST, &testFlowSensorReadingsOverride }, { MSG_ID_FP_FLOW_TEMP_OVERRIDE_REQUEST, &testFlowSensorTemperatureReadingsOverride }, { MSG_ID_FP_FILTERED_FLOW_RATE_OVERRIDE_REQUEST, &testFlowSensorFilteredReadingsOverride }, { MSG_ID_FP_FILTERED_FLOW_TEMP_OVERRIDE_REQUEST, &testFlowSensorFilteredTemperatureReadingsOverride }, { MSG_ID_FP_ALARM_STATE_OVERRIDE_REQUEST, &testAlarmStateOverride }, { MSG_ID_FP_ALARM_CLEAR_ALL_ALARMS_REQUEST, &testFPClearAllAlarms }, { MSG_ID_FP_CONDUCTIVITY_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testFPConductivitySensorDataPublishIntervalOverride }, { MSG_ID_FP_CONDUCTIVITY_OVERRIDE_REQUEST, &testFPConductivitySensorReadingsOverride }, { MSG_ID_FP_CONDUCTIVITY_TEMP_OVERRIDE_REQUEST, &testFPConductivitySensorTemperatureReadingsOverride }, { MSG_ID_FP_CONDUCTIVITY_READ_COUNT_OVERRIDE_REQUEST, &testFPConductivitySensorReadCounterOverride }, { MSG_ID_FP_CONDUCTIVITY_ERROR_COUNT_OVERRIDE_REQUEST, &testFPConductivitySensorErrorCounterOverride }, { MSG_ID_FP_FILTERED_COND_SENSOR_READINGS_OVERRIDE_REQUEST, &testFPConductivitySensorFilteredReadingsOverride }, { MSG_ID_FP_FILTERED_COND_SENSOR_TEMPERATURE_OVERRIDE_REQUEST, &testFPConductivitySensorFilteredTemperatureReadingsOverride }, { MSG_ID_DD_VOLTAGE_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testVoltageDataPublishIntervalOverride }, { MSG_ID_DD_MONITORED_VOLTAGE_OVERRIDE_REQUEST, &testVoltageOverride }, { MSG_ID_FP_LEVEL_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testFPLevelsDataPublishIntervalOverride }, { MSG_ID_FP_LEVEL_OVERRIDE_REQUEST, &testFPLevelStateOverride }, { MSG_ID_FP_PERMEATE_TANK_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testPermeateTankDataPublishIntervalOverride }, { MSG_ID_FP_RO_PUMP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testROPumpDataPublishIntervalOverride }, { MSG_ID_DD_RINSE_PUMP_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testRinsePumpDataPublishIntervalOverride }, { MSG_ID_FP_SET_START_STOP_OVERRIDE_REQUEST, &testSetGeneratePermeateSignal }, { MSG_ID_FP_RO_REJECTION_RATIO_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testRORejectionRatioDataPublishIntervalOverride }, { MSG_ID_FP_RO_FILTERED_REJECTION_RATIO_OVERRIDE_REQUEST, &testRORejectionRatioFilteredOverride }, }; /// Calculation for number of entries in the incoming message function handler look-up table. #define NUM_OF_FUNCTION_HANDLERS (sizeof(MSG_FUNCTION_HANDLER_LOOKUP) / sizeof(MSG_HANDLER_LOOKUP_T)) // ********** private data ********** static BOOL testerLoggedIn = FALSE; ///< Flag indicates whether tester logged in or not. static volatile U16 nextSeqNo = 1; ///< Next sequence number. /// List of message IDs that are requested not to be transmitted. //static BLOCKED_MSGS_DATA_T blockedMessagesForXmit = { 0, 0, 0, 0, 0, 0, 0, 0 }; /// UI version information static UI_VERSIONS_T uiVersionRecord = { 0, 0, 0, 0, 0 }; // ********** private function prototypes ********** static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); /*********************************************************************//** * @brief * The serializeMessage function serializes a given message into a given * array of bytes. A sequence # is added to the message here and the ACK * bit of the sequence # is set if ACK is required per parameter. A sync byte * is inserted at the beginning of the message and an 8-bit CRC is appended to * the end of the message. The message is queued for transmission in the given buffer. * @details \b Inputs: none * @details \b Outputs: given data array populated with serialized message data and * queued for transmit. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when pending ACK list is full. * @param msg message to serialize * @param buffer outgoing buffer that message should be queued in * @param ackReq is an acknowledgement from receiver required? * @return size (in bytes) of serialized message populated in given data array. *************************************************************************/ U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) { BOOL result = FALSE; BOOL error = FALSE; U32 msgSize = 0; U32 sizeMod, sizePad; U32 i; U08 crc; U08 data[ MAX_ACK_MSG_SIZE ]; // byte array to populate with message data // prefix data with message sync byte data[ msgSize++ ] = MESSAGE_SYNC_BYTE; // set sequence # and ACK bit (unless this is an ACK to a received message) if ( msg.hdr.msgID != MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK ) { // thread protect next sequence # access & increment _disable_IRQ(); msg.hdr.seqNo = nextSeqNo; nextSeqNo = INC_WRAP( nextSeqNo, MIN_MSG_SEQ_NO, MAX_MSG_SEQ_NO ); _enable_IRQ(); if ( TRUE == ackReq ) { msg.hdr.seqNo *= -1; } } // calculate message CRC crc = crc8( (U08*)(&msg), sizeof( MESSAGE_HEADER_T ) + msg.hdr.payloadLen ); // serialize message header data memcpy( &data[ msgSize ], &( msg.hdr ), sizeof( MESSAGE_HEADER_T ) ); msgSize += sizeof( MESSAGE_HEADER_T ); // serialize message payload (only used bytes per payloadLen field) memcpy( &data[ msgSize ], &( msg.payload ), msg.hdr.payloadLen ); msgSize += msg.hdr.payloadLen; // add 8-bit CRC data[ msgSize++ ] = crc; // pad with zero bytes to get length a multiple of CAN_FRAME_PAYLOAD_SIZE (8) sizeMod = msgSize % CAN_FRAME_PAYLOAD_SIZE; sizePad = ( sizeMod == 0 ? 0 : CAN_FRAME_PAYLOAD_SIZE - sizeMod ); for ( i = 0; i < sizePad; i++ ) { data[ msgSize++ ] = 0; } // if ACK required, add to pending ACK list if ( TRUE == ackReq ) { if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) { error = TRUE; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL ) } } if ( FALSE == error ) { // add serialized message data to appropriate out-going comm buffer result = addToCommBuffer( buffer, data, msgSize ); } return result; } /*********************************************************************//** * @brief * The sendACKMsg function constructs and queues for transmit an ACK message * for a given received message. * @details \b Inputs: none * @details \b Outputs: ACK message queued for transmit on broadcast CAN channel. * @param message message to send an ACK for * @return TRUE if ACK message queued successfully, FALSE if not *************************************************************************/ BOOL sendACKMsg( MESSAGE_T *message ) { BOOL result; MESSAGE_T msg; // create a message record blankMessage( &msg ); // send ACK back with same seq. #, but w/o ACK bit msg.hdr.seqNo = message->hdr.seqNo * -1; // ACK messages always have this ID msg.hdr.msgID = MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK; // ACK messages always have no payload msg.hdr.payloadLen = 0; // serialize and queue the message for transmit on broadcast channel result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DD_BROADCAST, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The sendTestAckResponseMsg function constructs a simple response message for * a handled test message and queues it for transmit on the appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: response message constructed and queued for transmit. * @param msgID ID of handled message that we are responding to * @param buffer outgoing buffer that message should be queued in * @param ack TRUE if test message was handled successfully, FALSE if not * @return TRUE if response message successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendAckResponseMsg( MSG_ID_T msgID, COMM_BUFFER_T buffer, BOOL ack ) { BOOL result; MESSAGE_T msg; // create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; msg.hdr.payloadLen = sizeof( U08 ); msg.payload[ 0 ] = (U08)ack; // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, buffer, ACK_NOT_REQUIRED ); return result; } /*********************************************************************//** * @brief * The getMsgHandler function finds the appropriate handler function * for the given message. * @details \b Inputs: MSG_FUNCTION_HANDLER_LOOKUP[], MSG_FUNCTION_HANDLERS[] * @details \b Outputs: none * @param msgID ID of message to find handler function for * @return pointer to appropriate function to handle given message *************************************************************************/ static MsgFuncPtr getMsgHandler( U16 msgID ) { U32 i; MsgFuncPtr func = 0; // Search for the index associated with the given override command message ID and then use index to get the handling function for ( i = 0; i < NUM_OF_FUNCTION_HANDLERS; i++ ) { if ( MSG_FUNCTION_HANDLER_LOOKUP[i].msgID == msgID ) { func = MSG_FUNCTION_HANDLER_LOOKUP[i].msgHandler; break; } } return func; } /*********************************************************************//** * @brief * The handleIncomingMessage function calls the appropriate handler function * for the given message. * @details \b Inputs: none * @details \b Outputs: Appropriate message handler function called * @param message Incoming message to handle * @return none *************************************************************************/ void handleIncomingMessage( MESSAGE_T *message ) { BOOL ack = FALSE; // assume we will NAK until we have successful handling of message COMM_BUFFER_T respBuffer = tdResponseBuffers[ message->in_buffer ]; // if Dialin message, ensure Dialin is logged in before processing it if ( ( message->hdr.msgID < MSG_ID_FIRST_TD_TESTER_MESSAGE ) || ( MSG_ID_FIRST_DD_TESTER_MESSAGE == message->hdr.msgID ) || ( MSG_ID_FIRST_FP_TESTER_MESSAGE == message->hdr.msgID ) || ( TRUE == isTestingActivated() ) ) { MsgFuncPtr msgFuncPtr; // Find the appropriate message handling function to call msgFuncPtr = getMsgHandler( message->hdr.msgID ); // Ensure a handler is found before calling it if ( msgFuncPtr != 0 ) { // Call the appropriate message handling function ack = (*msgFuncPtr)( message ); } } // ACK/NAK request if ( message->hdr.msgID < MSG_ID_FIRST_TD_TESTER_MESSAGE ) { // only Sending Test ACK for dialin messages. } else { sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, ack ); } } // *********************************************************************** // ***************** Message Sending Helper Functions ******************** // *********************************************************************** /*********************************************************************//** * @brief * The sendEvent function constructs an DD event message to the UI and * queues the msg for transmit on the appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: DD event msg constructed and queued. * @param event Enumeration of event type that occurred * @param dat1 First data associated with event * @param dat2 Second data associated with event * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL sendEvent( DD_EVENT_ID_T event, EVENT_DATA_T dat1, EVENT_DATA_T dat2 ) { BOOL result; MESSAGE_T msg; EVENT_PAYLOAD_T eventStruct; eventStruct.event = (U32)event; eventStruct.dataType1 = (U32)dat1.dataType; eventStruct.data1 = dat1.data; eventStruct.dataType2 = (U32)dat2.dataType; eventStruct.data2 = dat2.data; // Create a message record blankMessage( &msg ); if ( ( event >= FP_EVENT_FIRST ) && ( event <= FP_EVENT_LAST ) ) { msg.hdr.msgID = MSG_ID_FP_EVENT; } else { msg.hdr.msgID = MSG_ID_DD_EVENT; } msg.hdr.payloadLen = sizeof( EVENT_PAYLOAD_T ); memcpy( &msg.payload, &eventStruct, sizeof( EVENT_PAYLOAD_T ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer // TODO : validate the change , DD -> UI channel removed and added DD broadcast instead. if ( msg.hdr.msgID == MSG_ID_FP_EVENT ) { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_FP_BROADCAST, ACK_NOT_REQUIRED ); } else { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DD_BROADCAST, ACK_NOT_REQUIRED ); } return result; } /*********************************************************************//** * @brief * The broadcastAlarmTriggered function constructs an alarm triggered msg to * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: alarm triggered msg constructed and queued. * @param alarm ID of alarm triggered * @param almData1 1st data associated with alarm * @param almData2 2nd data associated with alarm * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmTriggered( U32 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2, ALARM_SOURCE_T almSource ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; U32 data; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_TRIGGERED; msg.hdr.payloadLen = sizeof( U32 ) * 8; memcpy( payloadPtr, &alarm, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); data = (U32)almData1.dataType; memcpy( payloadPtr, &data, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); data = almData1.data.uInt.data; memcpy( payloadPtr, &data, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); data = (U32)almData2.dataType; memcpy( payloadPtr, &data, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); data = almData2.data.uInt.data; memcpy( payloadPtr, &data, sizeof( U32 ) ); // Pad with space for 3 U32s - set to zero - unused for DD payloadPtr += ( sizeof( U32) * 3 ); memset( payloadPtr, 0, sizeof( U32) * 3 ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer if ( ALM_SRC_FP == almSource ) { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_FP_ALARM, ACK_REQUIRED ); } else { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DD_ALARM, ACK_REQUIRED ); } return result; } /*********************************************************************//** * @brief * The broadcastAlarmCleared function constructs an alarm cleared msg to be * broadcast and queues the msg for transmit on the appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: alarm cleared msg constructed and queued. * @param alarm ID of alarm cleared * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmCleared( U32 alarm, ALARM_SOURCE_T almSource ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_CLEARED; msg.hdr.payloadLen = sizeof( U32 ); memcpy( payloadPtr, &alarm, sizeof( U32 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer if ( ALM_SRC_FP == almSource ) { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_FP_ALARM, ACK_REQUIRED ); } else { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DD_ALARM, ACK_REQUIRED ); } return result; } /*********************************************************************//** * @brief * The broadcastAlarmConditionCleared function constructs an alarm condition * cleared msg to be broadcast and queues the msg for transmit on the * appropriate CAN channel. * @details \b Inputs: none * @details \b Outputs: alarm condition cleared msg constructed and queued. * @param alarm ID of alarm which alarm condition is cleared * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastAlarmConditionCleared( U32 alarm, ALARM_SOURCE_T almSource ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_CONDITION_CLEARED; msg.hdr.payloadLen = sizeof( U32 ); memcpy( payloadPtr, &alarm, sizeof( U32 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer if ( ALM_SRC_FP == almSource ) { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_FP_ALARM, ACK_REQUIRED ); } else { result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DD_ALARM, ACK_REQUIRED ); } return result; } // *********************************************************************** // **************** Message Handling Helper Functions ******************** // *********************************************************************** /*********************************************************************//** * @brief * The handleSetTDOperationMode function receives the TD operation modes data * publish message. * @details \b Inputs: none * @details \b Outputs: none * @param message a pointer to the message to handle * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL handleSetTDOperationMode( MESSAGE_T *message ) { BOOL status = FALSE; U08* payloadPtr = message->payload; // HD mode broadcast is operations mode and submode so 8 bytes if ( message->hdr.payloadLen == sizeof( U32 ) + sizeof( U32 ) ) { U32 mode = 0; U32 subMode = 0; memcpy( &mode, payloadPtr, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); memcpy( &subMode, payloadPtr, sizeof( U32 ) ); setTDOperationMode( mode, subMode ); status = TRUE; } return status; } /*********************************************************************//** * @brief * The handleVersionRequestMessage function handles a UI request for DD * version information. * @details \b Message \b Sent: MSG_ID_DD_VERSION_REPONSE * @details \b Inputs: none * @details \b Outputs: UI version info. * @param message Pointer to the UI version request message which contains * the UI version information as well. * @return TRUE if request handled successfully, FALSE if not *************************************************************************/ BOOL handleVersionRequestMessage( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof( UI_VERSIONS_T ) ) { DD_VERSIONS_T ddVersionRecord; // Record UI version information memcpy( (U08*)(&uiVersionRecord), &message->payload, sizeof( UI_VERSIONS_T ) ); // Build DD version record ddVersionRecord.major = DD_VERSION_MAJOR; ddVersionRecord.minor = DD_VERSION_MINOR; ddVersionRecord.micro = DD_VERSION_MICRO; ddVersionRecord.build = DD_VERSION_BUILD; getFPGAVersions( &ddVersionRecord.fpgaId, &ddVersionRecord.fpgaMajor, &ddVersionRecord.fpgaMinor, &ddVersionRecord.fpgaLab ); ddVersionRecord.compatibilityRev = SW_COMPATIBILITY_REV; // Send DD version information result = sendMessage( MSG_ID_DD_VERSION_RESPONSE, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&ddVersionRecord, sizeof( DD_VERSIONS_T ) ); } return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The isTestingActivated function determines whether a tester has successfully * logged in to activate testing functionality. * @details \b Inputs: testerLoggedIn * @details \b Outputs: none * @return TRUE if a tester has logged in to activate testing, FALSE if not *************************************************************************/ BOOL isTestingActivated( void ) { return testerLoggedIn; } /*********************************************************************//** * @brief * The setTesterStatusToLoggedOut function sets the status of the tester to * logged out. * @details \b Inputs: none * @details \b Outputs: testerLoggedIn * @return none *************************************************************************/ void setTesterStatusToLoggedOut( void ) { testerLoggedIn = FALSE; } /*********************************************************************//** * @brief * The sendTestAckResponseMsg function constructs a simple response message for * a handled test message and queues it for transmit on the appropriate UART channel. * @details \b Inputs: none * @details \b Outputs: response message constructed and queued for transmit. * @param msgID ID of handled message that we are responding to * @param ack TRUE if test message was handled successfully, FALSE if not * @return TRUE if response message successfully queued for transmit, FALSE if not *************************************************************************/ static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ) { BOOL result; MESSAGE_T msg; // create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; msg.hdr.payloadLen = sizeof( U08 ); msg.payload[ 0 ] = (U08)ack; // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer // check msgID to determine what channel to use and default to DD's channels if( ( MSG_ID_FIRST_FP_TESTER_MESSAGE <= msgID ) && ( MSG_ID_TD_DEBUG_EVENT > msgID ) ) { result = serializeMessage( msg, COMM_BUFFER_OUT_FP_CAN_PC, ACK_NOT_REQUIRED ); } else { result = serializeMessage( msg, COMM_BUFFER_OUT_DD_CAN_PC, ACK_NOT_REQUIRED ); } return result; } /*********************************************************************//** * @brief * The handleTesterLogInRequest function handles a request to login as a tester. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL handleTesterLogInRequest( MESSAGE_T *message ) { // verify pass code // TODO - placeholder - how do we want to authenticate tester? if ( ( 3 == message->hdr.payloadLen ) && ( 0x31 == message->payload[ 0 ] ) && ( 0x32 == message->payload[ 1 ] ) && ( 0x33 == message->payload[ 2 ] ) ) { testerLoggedIn = TRUE; // The user logged in, so the set the dialin expiration date until the first check in from dialin is received setDialinCheckInTimeStamp(); } else { testerLoggedIn = FALSE; } return testerLoggedIn; } /*********************************************************************//** * @brief * The handleTesterFPLogInRequest function handles a request to login as a tester. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL handleTesterFPLogInRequest( MESSAGE_T *message ) { // verify pass code // TODO - placeholder - how do we want to authenticate tester? if ( ( 3 == message->hdr.payloadLen ) && ( 0x31 == message->payload[ 0 ] ) && ( 0x32 == message->payload[ 1 ] ) && ( 0x33 == message->payload[ 2 ] ) ) { testerLoggedIn = TRUE; // The user logged in, so the set the dialin expiration date until the first check in from dialin is received setDialinCheckInTimeStamp(); } else { testerLoggedIn = FALSE; } return testerLoggedIn; } /*********************************************************************//** * @brief * The handleTDSoftwareResetRequest function handles a request to reset the * TD firmware processor. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return FALSE if reset command rejected (won't return if reset successful) *************************************************************************/ BOOL handleDDSoftwareResetRequest( MESSAGE_T *message ) { BOOL result = FALSE; // Verify payload length if ( 0 == message->hdr.payloadLen ) { // S/w reset of processor result = TRUE; // Reset will prevent this from getting transmitted though setSystemREG1_SYSECR( (0x2) << 14 ); // Reset processor } return result; } /*********************************************************************//** * @brief * The testSetTestConfiguration function handles a request to set a * test configuration. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return TRUE if command accepted, FALSE if rejected *************************************************************************/ BOOL testSetTestConfiguration( MESSAGE_T *message ) { BOOL result = FALSE; // Verify payload length if ( sizeof( TEST_CONFIG_PAYLOAD_T ) == message->hdr.payloadLen ) { TEST_CONFIG_PAYLOAD_T payload; // copy message payload to local variable memcpy( (U08*)&payload, &message->payload[0], sizeof( TEST_CONFIG_PAYLOAD_T ) ); // Verify given test configuration is valid if ( payload.config < NUM_OF_TEST_CONFIGS ) { result = TRUE; if ( FALSE == payload.reset ) { setTestConfig( (TEST_CONFIG_T)payload.config ); } else { resetTestConfig( (TEST_CONFIG_T)payload.config ); } } } return result; } /*********************************************************************//** * @brief * The testGetTestConfiguration function handles a request to get a * test configuration. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL testGetTestConfiguration( MESSAGE_T *message ) { BOOL result = FALSE; // verify payload length if ( 0 == message->hdr.payloadLen ) { result = sendTestConfigStatusToDialin(); } return result; } /*********************************************************************//** * @brief * The testResetTestConfiguration function handles a request to reset all * test configurations. * @details \b Inputs: none * @details \b Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ BOOL testResetAllTestConfigurations( MESSAGE_T *message ) { BOOL result = FALSE; // verify payload length if ( 0 == message->hdr.payloadLen ) { result = resetAllTestConfigs(); } return result; } /**@}*/