/************************************************************************** * * Copyright (c) 2024-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 AirPump.c * * @author (last) Dara Navaei * @date (last) 19-Dec-2025 * * @author (original) Sean Nash * @date (original) 19-Sep-2024 * ***************************************************************************/ #include "AirPump.h" #include "AlarmMgmtTD.h" #include "FpgaTD.h" #include "Messaging.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "TaskGeneral.h" #include "Timers.h" /** * @addtogroup AirPump * @{ */ // ********** private definitions ********** #define AIR_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Air pump data publish interval. #define DATA_PUBLISH_COUNTER_START_COUNT 13 ///< Air pump data publish start counter. #pragma pack(push, 1) /// Payload record structure for air pump test set command message payload. typedef struct { U32 h12State; ///< Air pump state to command. F32 h12Power; ///< Air pump power level to command. } AIR_PUMP_SET_CMD_PAYLOAD_T; #pragma pack(pop) // ********** private data ********** static AIR_PUMP_STATE_T currentAirPumpState; ///< Current air pump control state. static U16 currentAirPumpRPM; ///< Current air pump RPM. static F32 currentAirPumpPowerLevel; ///< Current air pump power level setting in % duty cycle (0..100%). static U32 airPumpDataPublicationTimerCounter; ///< Air pump data broadcast timer counter. static OVERRIDE_U32_T airPumpDataPublishInterval; ///< Air pump data broadcast interval (in ms). // ********** private function prototypes ********** static AIR_PUMP_STATE_T handleAirPumpStartState( void ); static AIR_PUMP_STATE_T handleAirPumpOffState( void ); static AIR_PUMP_STATE_T handleAirPumpOnState ( void ); static void publishAirPumpData( void ); /*********************************************************************//** * @brief * The initAirPump function initializes the air pump driver. * @details \b Inputs: none * @details \b Outputs: Air pump driver unit initialized * @return none *************************************************************************/ void initAirPump(void) { // Initialize driver initGasLiqXferPumpDriver(); // Initialize controller variables airPumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; currentAirPumpState = AIR_PUMP_STATE_INIT; currentAirPumpPowerLevel = AIR_PUMP_MOTOR_OFF; airPumpDataPublishInterval.data = AIR_PUMP_DATA_PUB_INTERVAL; airPumpDataPublishInterval.ovData = AIR_PUMP_DATA_PUB_INTERVAL; airPumpDataPublishInterval.ovInitData = AIR_PUMP_DATA_PUB_INTERVAL; airPumpDataPublishInterval.override = OVERRIDE_RESET; } /*********************************************************************//** * @brief * The setAirPumpState function sets the current air pump state machine state. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid state given. * @details \b Inputs: currentAirPumpState * @details \b Outputs: currentAirPumpState, currentAirPumpMotorPowerLevel * @param state Air pump state to set * @param power Power level to set air pump to * @return TRUE if set else FALSE *************************************************************************/ BOOL setAirPumpState( AIR_PUMP_STATE_T state, F32 power ) { BOOL result = FALSE; //There is a limitation on the TD circuit to be able to run the pump at the low speed. change planned in next version of the board. right now limiting the pump duty cycle below 24% //BOOL validInput = ( power == AIR_PUMP_DUTY_CYCLE_MIN) || ( power >= AIR_PUMP_DUTY_CYCLE_LIMIT && power <= AIR_PUMP_DUTY_CYCLE_MAX); BOOL validInput = ( ( ( power >= AIR_PUMP_DUTY_CYCLE_MIN ) && ( power <= AIR_PUMP_DUTY_CYCLE_MAX ) ) && ( FALSE == ( ( power > AIR_PUMP_DUTY_CYCLE_MIN ) && ( power < AIR_PUMP_DUTY_CYCLE_LIMIT ) ) ) ); // need to pass the result immediately to user when user enter invalid range if ( FALSE == validInput ) { result = FALSE; } else if ( state >= AIR_PUMP_STATE_INIT && state < NUM_OF_AIR_PUMP_STATES ) { currentAirPumpState = state; // power level should be 0 (OFF) when pump state is not ON if ( state != AIR_PUMP_STATE_ON ) { power = AIR_PUMP_MOTOR_OFF; } currentAirPumpPowerLevel = power; result = TRUE; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_AIR_PUMP_INVALID_STATE1, (U32)state ) result = FALSE; } return result; } /*********************************************************************//** * @brief * The getAirPumpState function returns the current air pump state machine. * @details \b Inputs: currentAirPumpState * @details \b Outputs: none * @return current state of the air pump state machine. *************************************************************************/ AIR_PUMP_STATE_T getAirPumpState( void ) { return currentAirPumpState; } /*********************************************************************//** * @brief * The execAirPumpController function executes the air pump state machine. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if the current state is invalid. * @details \b Inputs: currentAirPumpState * @details \b Outputs: currentAirPumpState * @return none *************************************************************************/ void execAirPumpController( void ) { // update the speed every tick currentAirPumpRPM = getAirPumpMotorRPM(); switch( currentAirPumpState ) { case AIR_PUMP_STATE_INIT: currentAirPumpState = handleAirPumpStartState(); break; case AIR_PUMP_STATE_OFF: currentAirPumpState = handleAirPumpOffState(); break; case AIR_PUMP_STATE_ON: currentAirPumpState = handleAirPumpOnState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_AIR_PUMP_INVALID_STATE2, (U32)currentAirPumpState ) break; } publishAirPumpData(); } /*********************************************************************//** * @brief * The handleAirPumpStartState function starts the air pump state machine. * @details \b Inputs: none * @details \b Outputs: none * @return next state of the air pump state machine *************************************************************************/ static AIR_PUMP_STATE_T handleAirPumpStartState( void ) { AIR_PUMP_STATE_T state = AIR_PUMP_STATE_OFF; return state; } /*********************************************************************//** * @brief * The handleAirPumpOffState function stops the air pump * @details \b Inputs: none * @details \b Outputs: Air pump motor turned off * @return next state of the air pump state machine *************************************************************************/ static AIR_PUMP_STATE_T handleAirPumpOffState( void ) { AIR_PUMP_STATE_T state = AIR_PUMP_STATE_OFF; if ( getAirPumpMotorPower() != 0 ) { currentAirPumpPowerLevel = 0; setAirPumpMotorPower( currentAirPumpPowerLevel ); } return state; } /*********************************************************************//** * @brief * The handleAirPumpOnState function starts the air pump * @details \b Inputs: none * @details \b Outputs: Air pump motor turned on. * @return next state of the air pump state machine *************************************************************************/ static AIR_PUMP_STATE_T handleAirPumpOnState( void ) { AIR_PUMP_STATE_T state = AIR_PUMP_STATE_ON; if ( getAirPumpMotorPower() != currentAirPumpPowerLevel ) { setAirPumpMotorPower( currentAirPumpPowerLevel ); } return state; } /*********************************************************************//** * @brief * The publishAirPumpData function constructs and sends the air pump data * broadcast message. * @details \b Message \b Sent: MSG_ID_TD_AIR_PUMP_DATA * @details \b Inputs: airPumpDataPublicationTimerCounter, currentAirPumpState * @details \b Outputs: airPumpDataPublicationTimerCounter * @return none *************************************************************************/ static void publishAirPumpData( void ) { currentAirPumpPowerLevel = getAirPumpMotorPower(); // update local power setting from driver if ( ++airPumpDataPublicationTimerCounter >= getU32OverrideValue( &airPumpDataPublishInterval ) ) { AIR_PUMP_PAYLOAD_T data; data.h12State = getAirPumpState(); data.h12Power = currentAirPumpPowerLevel; data.h12Rpm = (U32)currentAirPumpRPM; //TODO:remove after validating pump speed data.fpgah12Rpm = getAirPumpMotorFPGARPM(); //TODO:remove after validating pump speed data.scalarPower = getAirPumpMotorScalarPower(); broadcastData( MSG_ID_TD_AIR_PUMP_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( AIR_PUMP_PAYLOAD_T ) ); airPumpDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testAirPumpDataPublishIntervalOverride function overrides the interval * at which the TD air pump data is published. * @details \b Inputs: none * @details \b Outputs: airPumpDataPublishInterval * @param message Override message from Dialin which includes the interval * (in ms) to override the air pump broadcast interval to. * @return TRUE if override request is successful, FALSE if not *************************************************************************/ BOOL testAirPumpDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &airPumpDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testSetAirPump function sets the air pump to a given power level. * @details \b Inputs: none * @details \b Outputs: currentAirPumpMotorPowerLevel * @param message set message from Dialin which includes the state to set * the air pump to. * @return TRUE if set request is successful, FALSE if not *************************************************************************/ BOOL testSetAirPump( MESSAGE_T *message ) { BOOL result = FALSE; // Verify tester has logged in with TD and override type is valid if ( TRUE == isTestingActivated() ) { // Verify payload length is valid if ( sizeof( U32 ) + sizeof( U32 ) == message->hdr.payloadLen ) { U08 *msgPayload = &message->payload[0]; AIR_PUMP_SET_CMD_PAYLOAD_T payload; memcpy( &payload, msgPayload, sizeof( AIR_PUMP_SET_CMD_PAYLOAD_T ) ); result = setAirPumpState( (AIR_PUMP_STATE_T)payload.h12State, payload.h12Power ); } } return result; } /**@}*/