/************************************************************************** * * Copyright (c) 2019-2020 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 SystemComm.c * * @date 10-Oct-2019 * @author S. Nash * * @brief SystemComm service module. Provides system message communication \n * functionality. Messages can be queued for transmission. Incoming messages \n * are processed. * **************************************************************************/ #include // for memcpy() #include "DrainPump.h" #include "LoadCell.h" #include "MsgQueues.h" #include "OperationModes.h" #include "Reservoirs.h" #include "ROPump.h" #include "RTC.h" #include "SystemComm.h" #include "Utilities.h" #include "WatchdogMgmt.h" #include "SystemCommMessages.h" // ********** private definitions ********** #define ACK_REQUIRED TRUE #define ACK_NOT_REQUIRED FALSE #pragma pack(push,1) typedef struct { U32 alarmState; // 0 = no alarms, 1 = low priority, 2 = medium priority, 3 = high priority U32 alarmTop; // ID of top active alarm U32 escalatesIn; // seconds U32 silenceExpiresIn; // seconds U16 alarmsFlags; // bit flags: 1 = true, 0 = false for each bit } ALARM_COMP_STATUS_PAYLOAD_T; typedef struct { U32 treatmentTimePrescribedinSec; U32 treatmentTimeElapsedinSec; U32 treatmentTimeRemaininginSec; } TREATMENT_TIME_DATA_T; typedef struct { F32 loadCellA1inGram; F32 loadCellA2inGram; F32 loadCellB1inGram; F32 loadCellB2inGram; } LOAD_CELL_DATA_T; typedef struct { U32 setROPumpPressure; F32 measROFlowRate; F32 roPumpPWM; } RO_PUMP_DATA_T; typedef struct { U32 setDrainPumpSpeed; F32 drainPumpPWM; } DRAIN_PUMP_DATA_T; typedef struct { F32 roPumpInletPressure; F32 roPumpOutletPressure; F32 drainPumpInletPressure; F32 drainPumpOutletPressure; } PRESSURES_DATA_T; typedef struct { U32 activeReservoir; U32 fillToVolumeMl; U32 drainToVolumeMl; } RESERVOIR_DATA_T; #pragma pack(pop) // ********** private data ********** static BOOL testerLoggedIn = FALSE; static volatile U16 nextSeqNo = 1; // ********** private function prototypes ********** static U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ); static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); static BOOL sendAckResponseMsg( MSG_ID_T msgID, COMM_BUFFER_T buffer, BOOL ack ); /************************************************************************* * @brief serializeMessage * The serializeMessage function serializes a given message into a given \n * array of bytes. A sequence # is added to the message here and the ACK \n * bit of the sequence # is set if ACK is required per parameter. A sync byte \n * is inserted at the beginning of the message and an 8-bit CRC is appended to \n * the end of the message. The message is queued for transmission in the given buffer. * @details * Inputs : none * Outputs : given data array populated with serialized message data and queued for transmit. * @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. *************************************************************************/ static U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) { BOOL result = 0; 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 ) { // 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_MESSAGE_PAYLOAD_SIZE (8) sizeMod = msgSize % CAN_MESSAGE_PAYLOAD_SIZE; sizePad = ( sizeMod == 0 ? 0 : CAN_MESSAGE_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_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 sendACKMsg * The sendACKMsg function constructs and queues for transmit an ACK message \n * for a given received message. * @details * Inputs : none * 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; // 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_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief sendTestAckResponseMsg * The sendTestAckResponseMsg function constructs a simple response \n * message for a handled test message and queues it for transmit on the \n * appropriate UART channel. * @details * Inputs : none * 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 *************************************************************************/ static 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; } // *********************************************************************** // ***************** Message Sending Helper Functions ******************** // *********************************************************************** /************************************************************************* * @brief broadcastAlarmTriggered * The broadcastAlarmTriggered function constructs an alarm triggered msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * 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( U16 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_TRIGGERED; msg.hdr.payloadLen = sizeof( U16 ) + sizeof( ALARM_DATA_T ) + sizeof( ALARM_DATA_T ); memcpy( payloadPtr, &alarm, sizeof( U16 ) ); payloadPtr += sizeof( U16 ); memcpy( payloadPtr, &almData1, sizeof( ALARM_DATA_T ) ); payloadPtr += sizeof( ALARM_DATA_T ); memcpy( payloadPtr, &almData2, sizeof( ALARM_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_ALARM, ACK_REQUIRED ); return result; } /************************************************************************* * @brief broadcastAlarmCleared * The broadcastAlarmCleared function constructs an alarm cleared msg to be \n * broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * 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( U16 alarm ) { 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( U16 ); memcpy( payloadPtr, &alarm, sizeof( U16 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_ALARM, ACK_REQUIRED ); return result; } /************************************************************************* * @brief broadcastRTCEpoch * The broadcastRTCEpoch function constructs an epoch msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : RTC time and date in epoch * @param epoch : Current time and date in epoch * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastRTCEpoch( U32 epoch ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_RTC_EPOCH; msg.hdr.payloadLen = sizeof( U32 ); memcpy( payloadPtr, &epoch, sizeof( U32 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastDGHDOperationMode function constructs a DG operation mode \n * broadcast message and queues the msg for transmit on the appropriate CAN channel. * @details * Inputs : none * Outputs : DG operation mode msg constructed and queued * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastDGOperationMode( U32 mode ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DG_OP_MODE; msg.hdr.payloadLen = sizeof( U32 ); memcpy( payloadPtr, &mode, sizeof( U32 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastLoadCellData function sends out load cell data. * @details * Inputs : none * Outputs : load cell data msg constructed and queued * @param loadCellA1 : load cell A 1 data in grams. * @param loadCellA2 : load cell A 2 data in grams. * @param loadCellB1 : load cell B 1 data in grams. * @param loadCellB2 : load cell B 2 data in grams. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastLoadCellData( F32 loadCellA1, F32 loadCellA2, F32 loadCellB1, F32 loadCellB2 ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; LOAD_CELL_DATA_T payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_LOAD_CELL_READINGS; msg.hdr.payloadLen = sizeof( LOAD_CELL_DATA_T ); payload.loadCellA1inGram = loadCellA1; payload.loadCellA2inGram = loadCellA2; payload.loadCellB1inGram = loadCellB1; payload.loadCellB2inGram = loadCellB2; memcpy( payloadPtr, &payload, sizeof( LOAD_CELL_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastROPumpData function sends out RO pump data. * @details * Inputs : none * Outputs : RO pump data msg constructed and queued * @param tgtPressure : target pressure for RO pump in PSI. * @param measFlow : measure RO flow rate in LPM. * @param setPWM : set PWM duty cycle in %. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastROPumpData( U32 tgtPressure, F32 measFlow, F32 setPWM ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; RO_PUMP_DATA_T payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_RO_PUMP_DATA; msg.hdr.payloadLen = sizeof( RO_PUMP_DATA_T ); payload.setROPumpPressure = tgtPressure; payload.measROFlowRate = measFlow; payload.roPumpPWM = setPWM; memcpy( payloadPtr, &payload, sizeof( RO_PUMP_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastDrainPumpData function sends out RO pump data. * @details * Inputs : none * Outputs : Drain pump data msg constructed and queued * @param tgtSpeed : target speed for drain pump in RPM. * @param setPWM : set PWM duty cycle in %. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastDrainPumpData( U32 tgtSpeed, F32 setPWM ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; DRAIN_PUMP_DATA_T payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DRAIN_PUMP_DATA; msg.hdr.payloadLen = sizeof( DRAIN_PUMP_DATA_T ); payload.setDrainPumpSpeed = tgtSpeed; payload.drainPumpPWM = setPWM; memcpy( payloadPtr, &payload, sizeof( DRAIN_PUMP_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastPressureSensorsData function sends out DG pressure data. * @details * Inputs : none * Outputs : Pressure data msg constructed and queued * @param measROIn : measured RO pump inlet pressure in PSI. * @param measROOut : measured RO pump outlet pressure in PSI. * @param measDrainIn : measured Drain pump inlet pressure in PSI. * @param measDrainOut : measured Drain pump outlet pressure in PSI. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastPressureSensorsData( F32 measROIn, F32 measROOut, F32 measDrainIn, F32 measDrainOut ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; PRESSURES_DATA_T payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DG_PRESSURES_DATA; msg.hdr.payloadLen = sizeof( PRESSURES_DATA_T ); payload.roPumpInletPressure = measROIn; payload.roPumpOutletPressure = measROOut; payload.drainPumpInletPressure = measDrainIn; payload.drainPumpOutletPressure = measDrainOut; memcpy( payloadPtr, &payload, sizeof( PRESSURES_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief * The broadcastReservoirData function broadcasts the DG reservoir data. * @details * Inputs : none * Outputs : Reservoir data msg constructed and queued * @param resID : ID of currently active reservoir. * @param fillToVol : Current target fill to volume for inactive reservoir. * @param drainToVol : Current target drain to volume for inactive reservoir. * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ BOOL broadcastReservoirData( U32 resID, U32 fillToVol, U32 drainToVol ) { BOOL result; MESSAGE_T msg; U08 *payloadPtr = msg.payload; RESERVOIR_DATA_T payload; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DG_PRESSURES_DATA; msg.hdr.payloadLen = sizeof( RESERVOIR_DATA_T ); payload.activeReservoir = resID; payload.fillToVolumeMl = fillToVol; payload.drainToVolumeMl = drainToVol; memcpy( payloadPtr, &payload, sizeof( RESERVOIR_DATA_T ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; } // *********************************************************************** // **************** Message Handling Helper Functions ******************** // *********************************************************************** /************************************************************************* * @brief * The handlePowerOffWarning function handles a power off warning message \n * from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handlePowerOffWarning( MESSAGE_T *message ) { // TODO - signal modules that require a warning } /************************************************************************* * @brief * The handleSetDialysateTemperatureCmd function handles a dialysate temperature \n * set points message from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleSetDialysateTemperatureCmd( MESSAGE_T *message ) { // TODO - parse and send temp targets to heaters module } /************************************************************************* * @brief * The handleFWVersionCmd function handles a FW version request message. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleFWVersionCmd( MESSAGE_T *message ) { MESSAGE_T msg; U08 *payloadPtr = msg.payload; U08 major = (U08)DG_VERSION_MAJOR; U08 minor = (U08)DG_VERSION_MINOR; U16 build = (U16)DG_VERSION_BUILD; // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DG_VERSION; msg.hdr.payloadLen = sizeof( U08 ) + sizeof( U08 ) + sizeof( U16 ); memcpy( payloadPtr, &major, sizeof( U08 ) ); payloadPtr += sizeof( U08 ); memcpy( payloadPtr, &minor, sizeof( U08 ) ); payloadPtr += sizeof( U08 ); memcpy( payloadPtr, &build, sizeof( U16 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); } /************************************************************************* * @brief * The handleSwitchReservoirCmd function handles a switch reservoirs command \n * from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleSwitchReservoirCmd( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof(U32) ) { U32 reservoirID; result = TRUE; memcpy( &reservoirID, message->payload, sizeof(U32) ); setActiveReservoir( (RESERVOIR_ID_T)reservoirID ); } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } /************************************************************************* * @brief * The handleFillCmd function handles a fill command from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleFillCmd( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof(U32) ) { U32 fillToVolumeMl; result = TRUE; memcpy( &fillToVolumeMl, message->payload, sizeof(U32) ); startFill( fillToVolumeMl ); } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } /************************************************************************* * @brief * The handleDrainCmd function handles a drain command from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleDrainCmd( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof(U32) ) { U32 drainToVolMl; result = TRUE; memcpy( &drainToVolMl, message->payload, sizeof(U32) ); startDrain( drainToVolMl ); } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } /************************************************************************* * @brief * The handleStartStopTreatmentMsg function handles a treatment start/stop \n * message from the HD. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleStartStopTreatmentMsg( MESSAGE_T *message ) { BOOL result = FALSE; if ( message->hdr.payloadLen == sizeof(U32) ) { BOOL startingTreatment; result = TRUE; memcpy( &startingTreatment, message->payload, sizeof(U32) ); if ( MODE_STAN == getCurrentOperationMode() && TRUE == startingTreatment ) { requestNewOperationMode( MODE_CIRC ); } else if ( MODE_CIRC == getCurrentOperationMode() && FALSE == startingTreatment ) { requestNewOperationMode( MODE_STAN ); } else { result = FALSE; } } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /************************************************************************* * @brief sendDebugData * The sendDebugData function sends debug data out to the PC port. * @details * Inputs : none * Outputs : PC serial port * @param dbgData : Pointer to debug data * @param len : # of bytes of debug data * @return TRUE if debug data was successfully queued for transmit, FALSE if not *************************************************************************/ #ifdef DEBUG_ENABLED BOOL sendDebugData( U08 *dbgData, U32 len ) { BOOL result; // add serialized message data to appropriate comm buffer result = addToCommBuffer( COMM_BUFFER_OUT_UART_PC, dbgData, len ); return result; } #endif /************************************************************************* * @brief isTestingActivated * The isTestingActivated function determines whether a tester has successfully \n * logged in to activate testing functionality. * @details * Inputs : testerLoggedIn * Outputs : none * @param none * @return TRUE if a tester has logged in to activate testing, FALSE if not *************************************************************************/ BOOL isTestingActivated( void ) { return testerLoggedIn; } /************************************************************************* * @brief sendTestAckResponseMsg * The sendTestAckResponseMsg function constructs a simple response \n * message for a handled test message and queues it for transmit on the \n * appropriate UART channel. * @details * Inputs : none * 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 result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_PC, ACK_NOT_REQUIRED ); return result; } /************************************************************************* * @brief handleTesterLogInRequest * The handleTesterLogInRequest function handles a request to login as a \n * tester. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void 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; } else { testerLoggedIn = FALSE; } // respond to would be tester sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, testerLoggedIn ); } /************************************************************************* * @brief * The handleTestDGMessageRequest function handles a request to add a \n * DG message to the received message queue. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleTestDGMessageRequest( MESSAGE_T *message ) { MESSAGE_WRAPPER_T dgMessage; U32 msgLen = (U32)(message->hdr.payloadLen); U08 *msgBytes = (U08*)(&(dgMessage)); BOOL result; memcpy( msgBytes, message->payload, msgLen ); // add HD message to received message queue result = addToMsgQueue( MSG_Q_IN, &dgMessage ); // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } /************************************************************************* * @brief handleTestWatchdogCheckInStateOverrideRequest * The handleTestWatchdogCheckInStateOverrideRequest function handles a \n * request to override the check-in status of a given task. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC_U32( BOOL, handleTestWatchdogCheckInStateOverrideRequest, testSetWatchdogTaskCheckInOverride, testResetWatchdogTaskCheckInOverride ) /************************************************************************* * @brief handleTestAlarmStateOverrideRequest * The handleTestAlarmStateOverrideRequest function handles a request to \n * override the active status of a given alarm. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC_U32( BOOL, handleTestAlarmStateOverrideRequest, testSetAlarmStateOverride, testResetAlarmStateOverride ) /************************************************************************* * @brief * The handleTestLoadCellOverrideRequest function handles a request to \n * override the value read from the given load cell. * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ DATA_ARRAY_OVERRIDE_HANDLER_FUNC_U32( BOOL, handleTestLoadCellOverrideRequest, testSetLoadCellOverride, testResetLoadCellOverride ) /************************************************************************* * @brief handleSetRTCTimestamp * The handleSetRTCTimestamp function handles a request to write time and * date to RTC * @details * Inputs : none * Outputs : message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ void handleSetRTCTimestamp( MESSAGE_T *message ) { BOOL result; U08 seconds = message->payload[0]; U08 minutes = message->payload[1]; U08 hours = message->payload[2]; U08 days = message->payload[3]; U08 months = message->payload[4]; U32 years; memcpy(&years, &message->payload[5], sizeof(U32)); // TODO: Change setRTCTimestamp to return a boolean for this result = TRUE; setRTCTimestamp( seconds, minutes, hours, days, months, years ); // respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); }