Index: firmware/App/Common.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Common.h (.../Common.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Common.h (.../Common.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -77,7 +77,7 @@ // **** Common Definitions **** -#define NEARLY_ZERO 0.00001 +#define NEARLY_ZERO 0.00000001 #define MASK_OFF_MSB 0x00FF #define MASK_OFF_LSB 0xFF00 #define MASK_OFF_MSW 0x0000FFFF @@ -86,12 +86,17 @@ #define SHIFT_16_BITS_FOR_WORD_SHIFT 16 #define FLOAT_TO_INT_ROUNDUP_OFFSET 0.5 #define ML_PER_LITER 1000 +#define MS_PER_SECOND 1000 +#define SEC_PER_MIN 60 +#define FRACTION_TO_PERCENT_FACTOR 100.0 // **** Common Macros **** +#define FLOAT_TO_INT_WITH_ROUND(f) ((f) < 0.0 ? (S32)((f) - FLOAT_TO_INT_ROUNDUP_OFFSET) : (S32)((f) + FLOAT_TO_INT_ROUNDUP_OFFSET)) #define CAP(v, u) ((v) > (u) ? (u) : (v)) #define RANGE(v, l, u) ((v) > (u) ? (u) : ((v) < (l) ? (l) : (v))) #define INC_WRAP(v, l, u) ((v) == (u) ? (l) : ((v) + 1)) +#define INC_CAP(v, u) ((v) == (u) ? (u) : ((v) + 1)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) #define MIN(a, b) ((a) > (b) ? (b) : (a)) #define GET_LSB_OF_WORD(w) ((U08)((w) & MASK_OFF_MSB)) @@ -101,6 +106,7 @@ #define MAKE_WORD_OF_BYTES(h, l) ((((U16)(h) << SHIFT_8_BITS_FOR_BYTE_SHIFT) & MASK_OFF_LSB) | ((U16)(l) & MASK_OFF_MSB)) #define MAKE_LONG_OF_WORDS(h, l) ((((U32)(h) << SHIFT_16_BITS_FOR_WORD_SHIFT) & MASK_OFF_LSW) | ((U32)(l) & MASK_OFF_MSW)) #define GET_TOGGLE(v, l, h) ((v) == (l) ? (h) : (l)) +#define BIT_BY_POS(p) (1U << (p)) #define SET_ALARM_WITH_1_U32_DATA(a,d1) { \ ALARM_DATA_T dat1; \ Index: firmware/App/Controllers/AlarmLamp.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Controllers/AlarmLamp.c (.../AlarmLamp.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Controllers/AlarmLamp.c (.../AlarmLamp.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -53,16 +53,16 @@ // ********** private data ********** -DATA_DECL( LAMP_PATTERN_T, LampPattern, currentLampPattern, LAMP_PATTERN_OFF, LAMP_PATTERN_FAULT ); -static LAMP_PATTERN_T pendingLampPattern = LAMP_PATTERN_OFF; +DATA_DECL( LAMP_PATTERN_T, LampPattern, currentLampPattern, LAMP_PATTERN_MANUAL, LAMP_PATTERN_FAULT ); +static LAMP_PATTERN_T pendingLampPattern = LAMP_PATTERN_MANUAL; static U32 currentLampPatternStep = 0; static U32 lampPatternStepTimer = 0; const struct LampPatterns lampPatterns[ NUM_OF_LAMP_PATTERNS ] = { { { 500, 500 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF } }, // LAMP_PATTERN_OFF { { 500, 500 }, { LAMP_STATE_ON, LAMP_STATE_ON }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF } }, // LAMP_PATTERN_OK - { { 500, 500 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_OFF } }, // LAMP_PATTERN_FAULT - { { 500, 500 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_OFF } }, // LAMP_PATTERN_HIGH_ALARM + { { 250, 250 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_OFF } }, // LAMP_PATTERN_FAULT + { { 250, 250 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_OFF } }, // LAMP_PATTERN_HIGH_ALARM { { 1000, 1000 }, { LAMP_STATE_ON, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_OFF } }, // LAMP_PATTERN_MED_ALARM { { 500, 500 }, { LAMP_STATE_ON, LAMP_STATE_ON }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_ON, LAMP_STATE_ON } }, // LAMP_PATTERN_LOW_ALARM { { 0, 0 }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF }, { LAMP_STATE_OFF, LAMP_STATE_OFF } } // LAMP_PATTERN_MANUAL @@ -86,7 +86,7 @@ *************************************************************************/ void initAlarmLamp( void ) { - pendingLampPattern = LAMP_PATTERN_OFF; + pendingLampPattern = LAMP_PATTERN_MANUAL; currentLampPatternStep = 0; lampPatternStepTimer = 0; @@ -218,6 +218,7 @@ { alarmLampSelfTestState = ALARM_LAMP_SELF_TEST_STATE_COMPLETE; setCPLDLampGreen( PIN_SIGNAL_LOW ); + requestAlarmLampPattern( LAMP_PATTERN_OK ); result = SELF_TEST_STATUS_PASSED; } break; Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -25,6 +25,7 @@ #include "FPGA.h" #include "InternalADC.h" #include "OperationModes.h" +#include "PIControllers.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" @@ -33,20 +34,19 @@ // ********** private definitions ********** -#define BLOOD_FLOW_DATA_PUB_INTERVAL (1000 / TASK_PRIORITY_INTERVAL) // interval (ms/task time) at which the blood flow data is published on the CAN bus +#define BLOOD_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) // interval (ms/task time) at which the blood flow data is published on the CAN bus -#define MAX_BLOOD_FLOW_RATE 600 // mL/min +#define MAX_BLOOD_FLOW_RATE 500 // mL/min +#define MIN_BLOOD_FLOW_RATE 100 // mL/min -#define MAX_BLOOD_PUMP_PWM_STEP_CHANGE 0.02 // duty cycle TODO - fixed or parameterized or set in motor controller? +#define MAX_BLOOD_PUMP_PWM_STEP_CHANGE 0.005 // max duty cycle change when ramping #define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.88 // controller will error if PWM duty cycle > 90%, so set max to 88% #define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.12 // controller will error if PWM duty cycle < 10%, so set min to 12% -#define BP_CONTROL_INTERVAL (500 / TASK_GENERAL_INTERVAL) // interval (ms/task time) at which the blood pump is controlled +#define BP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) // interval (ms/task time) at which the blood pump is controlled #define BP_P_COEFFICIENT 0.0002 // P term for blood pump control #define BP_I_COEFFICIENT 0.00002 // I term for blood pump control -#define BP_MAX_ERROR_SUM 10.0 // for anti-wind-up in I term -#define BP_MIN_ERROR_SUM -10.0 -#define BP_MAX_PWM_DC_DELTA 0.01 // prevents large steps in PWM duty cycle +#define BP_MAX_PWM_DC_DELTA 0.01 // prevents large steps in PWM duty cycle while controlling #define BP_MIN_PWM_DC_DELTA -0.01 #define BP_MAX_CURR_WHEN_STOPPED_MA 150.0 // motor controller current should not exceed this when pump should be stopped @@ -57,17 +57,20 @@ #define BP_SPEED_ADC_TO_RPM_FACTOR 1.375 // conversion factor from ADC counts to RPM for blood pump motor #define BP_CURRENT_ADC_TO_MA_FACTOR 2.65 // conversion factor from ADC counts to mA for blood pump motor -#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR (124.0 / ML_PER_LITER)// 124 pump revolutions = 1 liter or 1,000 mL +#define BP_REV_PER_LITER 124.0 // rotor revolutions per liter +#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) #define BP_GEAR_RATIO 32.0 // blood pump motor to blood pump gear ratio -#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 // ~32 BP motor RPM = 1% PWM duty cycle +#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003717 // ~27 BP motor RPM = 1% PWM duty cycle #define BP_PWM_ZERO_OFFSET 0.1 // 10% PWM duty cycle = zero speed -#define BP_PWM_FROM_ML_PER_MIN(rate) ((rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET) +#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) #define BLOODPUMP_ADC_FULL_SCALE_V 3.0 // BP analog signals are 0-3V (while int. ADC ref V is 3.3V) -#define BLOODPUMP_ADC_MID_PT_BITS ((F32)(INT_ADC_FULL_SCALE_BITS >> 1) * (BLOODPUMP_ADC_FULL_SCALE_V / INT_ADC_REF_V)) -#define SIGN_FROM_12_BIT_VALUE(v) ((S16)(v) - (S16)BLOODPUMP_ADC_MID_PT_BITS) +#define BLOODPUMP_ADC_MID_PT_BITS ( (F32)( INT_ADC_FULL_SCALE_BITS >> 1 ) * ( BLOODPUMP_ADC_FULL_SCALE_V / INT_ADC_REF_V ) ) +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_MID_PT_BITS ) -#define SIZE_OF_ROLLING_AVG 100 // flow samples in rolling average calculations +#define BLOOD_FLOW_SAMPLE_FREQ ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) +#define SIZE_OF_ROLLING_AVG (U32)( (F32)BLOOD_FLOW_SAMPLE_FREQ * 0.8 ) // measured blood flow is filtered w/ moving average +#define MAX_FLOW_FILTER_INTERVAL 5 // slowest sample interval for filter is every 5th sample typedef enum BloodPump_States { @@ -86,7 +89,7 @@ NUM_OF_BLOOD_FLOW_SELF_TEST_STATES } BLOOD_FLOW_SELF_TEST_STATE_T; -// CAN3 port pin assignments for pump stop and direction outputs +// pin assignments for pump stop and direction outputs #define STOP_CAN3_PORT_MASK 0x00000002 // (Tx - re-purposed as output GPIO for blood pump stop signal) #define DIR_CAN3_PORT_MASK 0x00000002 // (Rx - re-purposed as output GPIO for blood pump direction signal) // blood pump stop and direction macros @@ -113,13 +116,13 @@ DATA_DECL( F32, MeasuredBloodPumpMCSpeed, adcBloodPumpMCSpeedRPM, 0.0, 0.0 ); // measured blood pump motor controller speed DATA_DECL( F32, MeasuredBloodPumpMCCurrent, adcBloodPumpMCCurrentmA, 0.0, 0.0 );// measured blood pump motor controller current -static F32 bpFlowError = 0.0; // blood flow error -static F32 bpFlowErrorSum = 0.0; // blood flow error sum static U32 bpControlTimerCounter = 0; // determines when to perform control on blood flow static F32 flowReadings[ SIZE_OF_ROLLING_AVG ]; // holds flow samples for a rolling average static U32 flowReadingsIdx = 0; // index for next sample in rolling average array static F32 flowReadingsTotal = 0.0; // rolling total - used to calc average +static U32 flowReadingsCount = 0; // # of samples in flow rolling average buffer +static U32 flowReadingsTmrCtr = 0; // determines when to add samples to filter static U32 bpCurrErrorDurationCtr = 0; // used for tracking persistence of bp current errors @@ -136,6 +139,8 @@ static void releaseBloodPumpStop( void ); static void setBloodPumpDirection( MOTOR_DIR_T dir ); static void publishBloodFlowData( void ); +static void resetBloodFlowMovingAverage( void ); +static void filterBloodFlowReadings( F32 flow ); static void checkBloodPumpDirection( void ); static void checkBloodPumpMCCurrent( void ); static DATA_GET_PROTOTYPE( U32, getPublishBloodFlowDataInterval ); @@ -151,16 +156,16 @@ *************************************************************************/ void initBloodFlow( void ) { - U32 i; - stopBloodPump(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); // zero rolling flow average buffer - for ( i = 0; i < SIZE_OF_ROLLING_AVG; i++ ) - { - flowReadings[ i ] = 0.0; - } + resetBloodFlowMovingAverage(); + + // initialize blood flow PI controller + initializePIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, + BP_P_COEFFICIENT, BP_I_COEFFICIENT, + MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); } /************************************************************************* @@ -184,14 +189,11 @@ // verify flow rate if ( flowRate <= MAX_BLOOD_FLOW_RATE ) { + resetBloodFlowMovingAverage(); targetBloodFlowRate.data = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); bloodPumpDirection = dir; // set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we'll control to flow when ramp completed bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) - // reset flow control stats - bpFlowError = 0.0; - bpFlowErrorSum = 0.0; - bpControlTimerCounter = 0; switch ( bloodPumpState ) { @@ -233,11 +235,30 @@ } /************************************************************************* + * @brief signalBloodPumpHardStop + * The signalBloodPumpHardStop function stops the blood pump immediately. + * @details + * Inputs : none + * Outputs : Blood pump stopped, set point reset, state changed to off + * @param none + * @return none + *************************************************************************/ +void signalBloodPumpHardStop( void ) +{ + targetBloodFlowRate.data = 0; + stopBloodPump(); + bloodPumpState = BLOOD_PUMP_OFF_STATE; + bloodPumpPWMDutyCyclePct = 0.0; + bpControlTimerCounter = 0; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE ); +} + +/************************************************************************* * @brief execBloodFlowMonitor * The execBloodFlowMonitor function executes the blood flow monitor. * @details * Inputs : none - * Outputs : none + * Outputs : measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, adcBloodPumpMCCurrentmA * @param none * @return none *************************************************************************/ @@ -250,11 +271,7 @@ adcBloodPumpMCSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpRPM)) * BP_SPEED_ADC_TO_RPM_FACTOR; adcBloodPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * BP_CURRENT_ADC_TO_MA_FACTOR; - flowReadingsTotal -= flowReadings[ flowReadingsIdx ]; - flowReadings[ flowReadingsIdx ] = bpFlow; - flowReadingsTotal += bpFlow; - flowReadingsIdx = INC_WRAP( flowReadingsIdx, 0, SIZE_OF_ROLLING_AVG-1 ); - measuredBloodFlowRate.data = flowReadingsTotal / (F32)SIZE_OF_ROLLING_AVG; + filterBloodFlowReadings( bpFlow ); // don't start enforcing checks until out of init/POST mode if ( getCurrentOperationMode() != MODE_INIT ) @@ -320,13 +337,11 @@ if ( getTargetBloodFlowRate() != 0 ) { // set initial PWM duty cycle - bloodPumpPWMDutyCyclePctSet = MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ); + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET + MAX_BLOOD_PUMP_PWM_STEP_CHANGE; + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); // allow blood pump to run in requested direction setBloodPumpDirection( bloodPumpDirection ); releaseBloodPumpStop(); - // start PWM for blood pump - etpwmStartTBCLK(); isBloodPumpOn = TRUE; result = BLOOD_PUMP_RAMPING_UP_STATE; } @@ -353,19 +368,21 @@ { // start ramp down to stop bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ); + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); result = BLOOD_PUMP_RAMPING_DOWN_STATE; } // have we reached end of ramp up? else if ( bloodPumpPWMDutyCyclePctSet >= bloodPumpPWMDutyCyclePct ) { + resetBloodFlowMovingAverage(); + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } // continue ramp up else { bloodPumpPWMDutyCyclePctSet += MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ); + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } return result; @@ -394,13 +411,15 @@ // have we reached end of ramp down? else if ( bloodPumpPWMDutyCyclePctSet <= bloodPumpPWMDutyCyclePct ) { + resetBloodFlowMovingAverage(); + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } // continue ramp down else { bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ); + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } return result; @@ -421,32 +440,14 @@ BLOOD_PUMP_STATE_T result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; F32 tgtFlow = (F32)getTargetBloodFlowRate(); F32 actFlow = getMeasuredBloodFlowRate(); - F32 pTerm, iTerm; F32 newPWM; // control at set interval if ( ++bpControlTimerCounter >= BP_CONTROL_INTERVAL ) { - // compute P term - if ( MOTOR_DIR_FORWARD == bloodPumpDirectionSet ) - { - bpFlowError = tgtFlow - actFlow; - } - else - { - bpFlowError = (tgtFlow * -1.0) - (actFlow * -1.0); - } - pTerm = bpFlowError * BP_P_COEFFICIENT; - pTerm = RANGE( pTerm, BP_MIN_PWM_DC_DELTA, BP_MAX_PWM_DC_DELTA ); - // compute I term - bpFlowErrorSum += bpFlowError; - iTerm = RANGE( bpFlowErrorSum, BP_MIN_ERROR_SUM, BP_MAX_ERROR_SUM ); - iTerm *= BP_I_COEFFICIENT; - // compute new PWM duty cycle % for blood pump motor - newPWM = bloodPumpPWMDutyCyclePctSet + pTerm + iTerm; - newPWM = RANGE( newPWM, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); + newPWM = runPIController( PI_CONTROLLER_ID_BLOOD_FLOW, tgtFlow, actFlow ); bloodPumpPWMDutyCyclePctSet = newPWM; - etpwmSetCmpA( etpwmREG1, (U32)( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ); + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); bpControlTimerCounter = 0; } @@ -467,7 +468,6 @@ isBloodPumpOn = FALSE; bloodPumpPWMDutyCyclePctSet = 0.0; etpwmSetCmpA( etpwmREG1, 0 ); - etpwmStopTBCLK(); SET_BP_STOP(); } @@ -621,20 +621,113 @@ F32 measSpd = getMeasuredBloodPumpSpeed(); F32 measMCSpd = getMeasuredBloodPumpMCSpeed(); F32 measMCCurr = getMeasuredBloodPumpMCCurrent(); + F32 pumpPWMPctDutyCycle = bloodPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; #ifdef DEBUG_ENABLED // TODO - temporary debug code - remove later - S32 pwm = (S32)( 100.0 * bloodPumpPWMDutyCyclePctSet ); char debugFlowStr[ 256 ]; - sprintf( debugFlowStr, "Target Flow:%5d, Meas. Flow:%5d, Speed:%5d RPM, Current:%5d mA, PWM:%5d \n", flowStPt, (S32)measFlow, (S32)measMCSpd, (S32)measMCCurr, pwm ); + sprintf( debugFlowStr, "Blood Set Pt.:%5d, Meas. Flow:%5d, Speed:%5d RPM, Current:%5d mA, PWM:%5d \n", flowStPt, (S32)measFlow, (S32)measMCSpd, (S32)measMCCurr, (S32)pumpPWMPctDutyCycle ); sendDebugData( (U08*)debugFlowStr, strlen(debugFlowStr) ); #endif - broadcastBloodFlowData( flowStPt, measFlow, measRotSpd, measSpd, measMCSpd, measMCCurr ); + broadcastBloodFlowData( flowStPt, measFlow, measRotSpd, measSpd, measMCSpd, measMCCurr, pumpPWMPctDutyCycle ); bloodFlowDataPublicationTimerCounter = 0; } } /************************************************************************* + * @brief resetBloodFlowMovingAverage + * The resetBloodFlowMovingAverage function re-sizes and re-initializes the \n + * blood flow moving average sample buffer. + * @details + * Inputs : none + * Outputs : flowReadingsTotal, flowReadingsIdx, flowReadingsCount all set to zero. + * @param initFlow : the new blood flow set pt. + * @param flowDir : the new set direction + * @return none + *************************************************************************/ +static void resetBloodFlowMovingAverage( void ) +{ + flowReadingsTotal = 0.0; + flowReadingsIdx = 0; + flowReadingsCount = 0; + flowReadingsTmrCtr = 0; + bpControlTimerCounter = 0; +} + +/************************************************************************* + * @brief filterBloodFlowReadings + * The filterBloodFlowReadings function adds a new flow sample to the filter \n + * if decimation rate for current set point calls for it. + * @details + * Inputs : none + * Outputs : flowReadings[], flowReadingsIdx, flowReadingsCount + * @param flow : newest blood flow sample + * @return none + *************************************************************************/ +static void filterBloodFlowReadings( F32 flow ) +{ + BOOL addSampleToFilter = FALSE; + + if ( ( targetBloodFlowRate.data < MIN_BLOOD_FLOW_RATE ) || ( targetBloodFlowRate.data >= MAX_BLOOD_FLOW_RATE ) ) + { + addSampleToFilter = TRUE; + } + else + { + switch ( flowReadingsTmrCtr ) + { + case 0: + addSampleToFilter = TRUE; + break; + + case 1: + addSampleToFilter = FALSE; + break; + + case 2: + if ( targetBloodFlowRate.data >= 400 ) + { + addSampleToFilter = TRUE; + } + break; + + case 3: + if ( targetBloodFlowRate.data >= 200 ) + { + addSampleToFilter = TRUE; + } + break; + + case 4: + if ( targetBloodFlowRate.data >= 300 ) + { + addSampleToFilter = TRUE; + } + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_FILTER_STATE, flowReadingsTmrCtr ) + break; + } + } + + if ( TRUE == addSampleToFilter ) + { + if ( flowReadingsCount >= SIZE_OF_ROLLING_AVG ) + { + flowReadingsTotal -= flowReadings[ flowReadingsIdx ]; + } + flowReadings[ flowReadingsIdx ] = flow; + flowReadingsTotal += flow; + flowReadingsIdx = INC_WRAP( flowReadingsIdx, 0, SIZE_OF_ROLLING_AVG - 1 ); + flowReadingsCount = INC_CAP( flowReadingsCount, SIZE_OF_ROLLING_AVG ); + measuredBloodFlowRate.data = flowReadingsTotal / (F32)flowReadingsCount; + } + + flowReadingsTmrCtr = INC_WRAP( flowReadingsTmrCtr, 0, MAX_FLOW_FILTER_INTERVAL - 1 ); +} + +/************************************************************************* * @brief checkBloodPumpDirection * The checkBloodPumpDirection function checks the set direction vs. \n * the direction implied by the sign of the measured MC speed. Index: firmware/App/Controllers/BloodFlow.h =================================================================== diff -u -ref0b3f0ec00fadc50f95e0db1a6477fb4b076ea1 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision ef0b3f0ec00fadc50f95e0db1a6477fb4b076ea1) +++ firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Controllers/Buttons.c =================================================================== diff -u -rd71d1e6c2be627158cac9a8bc56adac7cdefd1c8 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Controllers/Buttons.c (.../Buttons.c) (revision d71d1e6c2be627158cac9a8bc56adac7cdefd1c8) +++ firmware/App/Controllers/Buttons.c (.../Buttons.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Drivers/Comm.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Drivers/Comm.c (.../Comm.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Drivers/Comm.c (.../Comm.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -26,8 +26,8 @@ // ********** private data ********** -static BOOL canXmitsInProgress = FALSE; -static BOOL uartXmitsInProgress = FALSE; +static volatile BOOL canXmitsInProgress = FALSE; +static volatile BOOL uartXmitsInProgress = FALSE; /************************************************************************* * @brief signalCANXmitsInitiated Index: firmware/App/Drivers/InternalADC.c =================================================================== diff -u -ref0b3f0ec00fadc50f95e0db1a6477fb4b076ea1 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Drivers/InternalADC.c (.../InternalADC.c) (revision ef0b3f0ec00fadc50f95e0db1a6477fb4b076ea1) +++ firmware/App/Drivers/InternalADC.c (.../InternalADC.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Drivers/InternalADC.h =================================================================== diff -u -ref0b3f0ec00fadc50f95e0db1a6477fb4b076ea1 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Drivers/InternalADC.h (.../InternalADC.h) (revision ef0b3f0ec00fadc50f95e0db1a6477fb4b076ea1) +++ firmware/App/Drivers/InternalADC.h (.../InternalADC.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Modes/ModeFault.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -47,8 +47,6 @@ *************************************************************************/ void transitionToFaultMode( void ) { - // temporary test code - solid red alarm lamp - requestAlarmLampPattern( LAMP_PATTERN_FAULT ); } /************************************************************************* Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -28,10 +28,10 @@ typedef enum POST_States { POST_STATE_START = 0, + POST_STATE_WATCHDOG, POST_STATE_ALARM_LAMP, - POST_STATE_STUCK_BUTTON, POST_STATE_FPGA, - POST_STATE_WATCHDOG, + POST_STATE_STUCK_BUTTON, POST_STATE_COMPLETED, POST_STATE_FAILED, NUM_OF_POST_STATES @@ -77,7 +77,6 @@ *************************************************************************/ void transitionToInitAndPOSTMode( void ) { - requestAlarmLampPattern( LAMP_PATTERN_MANUAL ); } /************************************************************************* @@ -93,31 +92,33 @@ { SELF_TEST_STATUS_T testStatus = SELF_TEST_STATUS_IN_PROGRESS; + // TODO - send POST status on CAN + // execute current POST state switch ( postState ) { case POST_STATE_START: - postState = POST_STATE_ALARM_LAMP; + postState = POST_STATE_WATCHDOG; break; + case POST_STATE_WATCHDOG: + testStatus = execWatchdogTest(); + postState = handlePOSTStatus( testStatus ); // ignoring return value because last test + break; + case POST_STATE_ALARM_LAMP: testStatus = execAlarmLampTest(); postState = handlePOSTStatus( testStatus ); break; - case POST_STATE_STUCK_BUTTON: - testStatus = execStuckButtonTest(); - postState = handlePOSTStatus( testStatus ); - break; - case POST_STATE_FPGA: testStatus = execFPGATest(); postState = handlePOSTStatus( testStatus ); break; - case POST_STATE_WATCHDOG: - testStatus = execWatchdogTest(); - handlePOSTStatus( testStatus ); // ignoring return value because last test + case POST_STATE_STUCK_BUTTON: + testStatus = execStuckButtonTest(); + handlePOSTStatus( testStatus ); if ( TRUE == tempPOSTPassed ) { postState = POST_STATE_COMPLETED; @@ -139,18 +140,10 @@ break; case POST_STATE_FAILED: -#ifndef RM46_EVAL_BOARD_TARGET - // TODO - send POST status on CAN - // will want POST faults to wait for us to get here before sending us to fault mode - requestNewOperationMode( MODE_FAUL ); -#else - requestNewOperationMode( MODE_STAN ); -#endif - break; - + // should not get here - any failed post test should have already triggered a fault and taken us to fault mode default: - postState = POST_STATE_FAILED; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_MODE_INIT_POST_INVALID_POST_STATE, postState ) + postState = POST_STATE_FAILED; break; } } @@ -206,6 +199,7 @@ } else if ( testStatus == SELF_TEST_STATUS_FAILED ) { + requestAlarmLampPattern( LAMP_PATTERN_FAULT ); tempPOSTPassed = FALSE; result = POST_STATE_FAILED; } Index: firmware/App/Modes/ModeOpParams.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModeOpParams.c (.../ModeOpParams.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModeOpParams.c (.../ModeOpParams.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -55,7 +55,6 @@ void transitionToOpParamsMode( void ) { // temporary test code - alarm lamp fault - requestAlarmLampPattern( LAMP_PATTERN_FAULT ); setBloodPumpTargetFlowRate( 300, MOTOR_DIR_FORWARD ); #ifdef RM46_EVAL_BOARD_TARGET start = getMSTimerCount(); Index: firmware/App/Modes/ModePostTreat.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -55,7 +55,6 @@ void transitionToPostTreatmentMode( void ) { // temporary test code - alarm lamp high alarm - requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); setBloodPumpTargetFlowRate( 100, MOTOR_DIR_REVERSE ); #ifdef RM46_EVAL_BOARD_TARGET start = getMSTimerCount(); Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -55,7 +55,6 @@ void transitionToPreTreatmentMode( void ) { // temporary test code - alarm lamp low alarm - requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD ); #ifdef RM46_EVAL_BOARD_TARGET start = getMSTimerCount(); Index: firmware/App/Modes/ModePrescription.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModePrescription.c (.../ModePrescription.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModePrescription.c (.../ModePrescription.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -55,7 +55,6 @@ void transitionToPrescriptionMode( void ) { // temporary test code - alarm lamp Off - requestAlarmLampPattern( LAMP_PATTERN_OFF ); setBloodPumpTargetFlowRate( 500, MOTOR_DIR_FORWARD ); #ifdef RM46_EVAL_BOARD_TARGET // TODO - temporary test code for eval board Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -54,7 +54,6 @@ void transitionToStandbyMode( void ) { // temporary test code - alarm lamp OK - requestAlarmLampPattern( LAMP_PATTERN_OK ); setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD ); #ifdef RM46_EVAL_BOARD_TARGET start = getMSTimerCount(); Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -54,7 +54,6 @@ void transitionToTreatmentMode( void ) { // temporary test code - alarm lamp medium alarm - requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); setBloodPumpTargetFlowRate( 400, MOTOR_DIR_REVERSE ); #ifdef RM46_EVAL_BOARD_TARGET // TODO - temporary test code for eval board Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -27,6 +27,8 @@ #define ALARM_STATUS_PUBLISH_INTERVAL (500/TASK_GENERAL_INTERVAL) // 500ms / task interval +#define ALARM_SILENCE_EXPIRES_IN_SECS (60) + #pragma pack(push,1) typedef struct { @@ -55,7 +57,16 @@ { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_SPEED_CHECK { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE } // ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE } // ALARM_ID_WATCHDOG_EXPIRED }; const ALARM_DATA_T blankAlarmData = { ALARM_DATA_TYPE_NONE, 0 }; @@ -180,6 +191,8 @@ // no need to do anything if alarm is already active if ( FALSE == getAlarmActive( alarm ) ) { + // if alarms silenced, end silence due to new alarm + alarmStatus.alarmsSilenced = FALSE; // if alarm is a fault, request transition to fault mode if ( TRUE == alarmTable[ alarm ].alarmIsFault ) { @@ -221,7 +234,7 @@ // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ].data ) { - broadcastAlarmTriggered( alarm, blankAlarmData, blankAlarmData ); + broadcastAlarmTriggered( (U16)alarm, blankAlarmData, blankAlarmData ); } activateAlarm( alarm ); } @@ -243,7 +256,7 @@ // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ].data ) { - broadcastAlarmTriggered( alarm, alarmData, blankAlarmData ); + broadcastAlarmTriggered( (U16)alarm, alarmData, blankAlarmData ); } activateAlarm( alarm ); } @@ -266,7 +279,7 @@ // broadcast alarm and data if alarm not already active if ( FALSE == alarmIsActive[ alarm ].data ) { - broadcastAlarmTriggered( alarm, alarmData1, alarmData2 ); + broadcastAlarmTriggered( (U16)alarm, alarmData1, alarmData2 ); } activateAlarm( alarm ); } @@ -364,7 +377,7 @@ ALARM_ID_T a; BOOL faultsActive = FALSE; - // update FIFOs per alarm status table + // update FIFOs per active alarms table for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) { if ( TRUE == getAlarmActive(a) ) @@ -406,17 +419,14 @@ { case ALARM_PRIORITY_NONE: requestAlarmLampPattern( LAMP_PATTERN_OK ); - // TODO - no audio break; case ALARM_PRIORITY_LOW: requestAlarmLampPattern( LAMP_PATTERN_LOW_ALARM ); - // TODO - low priority audio break; case ALARM_PRIORITY_MEDIUM: requestAlarmLampPattern( LAMP_PATTERN_MED_ALARM ); - // TODO - medium priority audio break; case ALARM_PRIORITY_HIGH: @@ -428,10 +438,41 @@ { requestAlarmLampPattern( LAMP_PATTERN_HIGH_ALARM ); } + break; + + default: + requestAlarmLampPattern( LAMP_PATTERN_FAULT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) + break; + } + } + + if ( TRUE == alarmStatus.alarmsSilenced ) + { + // TODO - no audio + } + else // alarms not silenced + { + switch ( alarmStatus.alarmsState ) + { + case ALARM_PRIORITY_NONE: + // TODO - no audio + break; + + case ALARM_PRIORITY_LOW: + // TODO - low priority audio + break; + + case ALARM_PRIORITY_MEDIUM: + // TODO - medium priority audio + break; + + case ALARM_PRIORITY_HIGH: // TODO - high priority audio break; default: + // TODO - high priority audio SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, alarmStatus.alarmsState ) break; } @@ -442,14 +483,37 @@ * @brief updateAlarmsSilenceStatus * The updateAlarmsSilenceStatus function updates the alarms silence state. * @details - * Inputs : none - * Outputs : none + * Inputs : alarmStatus + * Outputs : alarmStatus * @param none * @return none *************************************************************************/ static void updateAlarmsSilenceStatus( void ) { + // if alarms not silenced, reset alarms silence related properties + if ( TRUE != alarmStatus.alarmsSilenced ) + { + alarmStatus.alarmsSilenceExpiresIn = 0; + alarmStatus.alarmsSilenceStart = 0; + } + else + { + U32 timeSinceAlarmSilenceStart = calcTimeSince( alarmStatus.alarmsSilenceStart ) / MS_PER_SECOND; + if ( timeSinceAlarmSilenceStart >= ALARM_SILENCE_EXPIRES_IN_SECS ) + { + alarmStatus.alarmsSilenceExpiresIn = 0; + } + else + { + alarmStatus.alarmsSilenceExpiresIn = ALARM_SILENCE_EXPIRES_IN_SECS - timeSinceAlarmSilenceStart; + } + // if alarms silence expires, end it + if ( 0 == alarmStatus.alarmsSilenceExpiresIn ) + { + alarmStatus.alarmsSilenced = FALSE; + } + } } /************************************************************************* @@ -463,7 +527,55 @@ *************************************************************************/ static void handleAlarmEscalations( void ) { + U32 secsToEscalate = 0; + ALARM_ID_T nextAlarmToEscalate = ALARM_ID_NO_ALARM; + ALARM_ID_T a; + // update escalations + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + { + if ( TRUE == getAlarmActive( a ) ) + { + // does active alarm escalate? + if ( ALARM_ID_NO_ALARM != alarmTable[ a ].alarmEscalatesTo ) + { + U32 secsRemaining = (S32)alarmTable[ a ].alarmEscalatesAfter - ( (S32)calcTimeSince( getAlarmStartTime( a ) / MS_PER_SECOND ) ); + + // time to escalate? + if ( secsRemaining <= 0 ) + { + activateAlarmNoData( alarmTable[ a ].alarmEscalatesTo ); + clearAlarm( a ); + } + else + { // no candidates for alarm escalation yet? + if ( ALARM_ID_NO_ALARM == nextAlarmToEscalate ) + { + secsToEscalate = secsRemaining; + nextAlarmToEscalate = a; + } + // sooner candidate for alarm escalation? + else if ( secsRemaining < secsToEscalate ) + { + secsToEscalate = secsRemaining; + nextAlarmToEscalate = a; + } + } + } // if alarm escalates + } // if alarm active + } // alarm table loop + + // update alarm escalation properties + if ( ALARM_ID_NO_ALARM == nextAlarmToEscalate ) + { + alarmStatus.alarmsToEscalate = FALSE; + alarmStatus.alarmsEscalatesIn = 0; + } + else + { + alarmStatus.alarmsToEscalate = TRUE; + alarmStatus.alarmsEscalatesIn = secsToEscalate; + } } /************************************************************************* @@ -478,7 +590,48 @@ *************************************************************************/ static void updateAlarmsFlags( void ) { + BOOL systemFault = FALSE; + BOOL stop = FALSE; + BOOL noClear = FALSE; + BOOL noResume = FALSE; + BOOL noRinseback = FALSE; + BOOL noEndTreatment = FALSE; + BOOL noNewTreatment = FALSE; + BOOL bypassDialyzer = FALSE; + ALARM_ID_T a; + // determine alarm flags + for ( a = ALARM_ID_NO_ALARM; a < NUM_OF_ALARM_IDS; a++ ) + { + if ( TRUE == getAlarmActive( a ) ) + { + systemFault = ( TRUE == alarmTable[ a ].alarmIsFault ? TRUE : systemFault ); + stop = ( TRUE == alarmTable[ a ].alarmStops ? TRUE : stop ); + noClear = ( TRUE == alarmTable[ a ].alarmNoClear ? TRUE : noClear ); + noResume = ( TRUE == alarmTable[ a ].alarmNoResume ? TRUE : noResume ); + noRinseback = ( TRUE == alarmTable[ a ].alarmNoRinseback ? TRUE : noRinseback ); + noEndTreatment = ( TRUE == alarmTable[ a ].alarmNoEndTreatment ? TRUE : noEndTreatment ); + noNewTreatment = ( TRUE == alarmTable[ a ].alarmNoNewTreatment ? TRUE : noNewTreatment ); + bypassDialyzer = ( TRUE == alarmTable[ a ].alarmDialyzerBypass ? TRUE : bypassDialyzer ); + + } // if alarm active + } // alarm table loop + + // do not bypass dialyzer if stop or fault flag set + if ( ( TRUE == systemFault ) || ( TRUE == stop ) ) + { + bypassDialyzer = FALSE; + } + + // set updated alarm flags + alarmStatus.systemFault = systemFault; + alarmStatus.stop = stop; + alarmStatus.noClear = noClear; + alarmStatus.noResume = noResume; + alarmStatus.noRinseback = noRinseback; + alarmStatus.noEndTreatment = noEndTreatment; + alarmStatus.noNewTreatment = noNewTreatment; + alarmStatus.bypassDialyzer = bypassDialyzer; } /************************************************************************* Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -31,6 +31,17 @@ ALARM_ID_BLOOD_PUMP_MC_SPEED_CHECK, ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, + ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, // 10 + ALARM_ID_DIAL_IN_PUMP_MC_SPEED_CHECK, + ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK, + ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK, + ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, + ALARM_ID_DIAL_OUT_PUMP_MC_SPEED_CHECK, // 15 + ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, + ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK, + ALARM_ID_WATCHDOG_EXPIRED, + ALARM_ID_RTC_COMM_ERROR, + ALARM_ID_RTC_CONFIG_ERROR, // 20 NUM_OF_ALARM_IDS } ALARM_ID_T; @@ -60,6 +71,7 @@ BOOL alarmsSilenced; // alarms are currently silenced? U32 alarmsSilenceStart; // time stamp for when alarms were silenced (ms) U32 alarmsSilenceExpiresIn; // time until alarm silence expires (seconds) + BOOL alarmsToEscalate; // are any active alarms due to escalate (should UI show count down timer?) U32 alarmsEscalatesIn; // time until alarm will escalate (seconds) ALARM_ID_T alarmTop; // ID of current top alarm that will drive lamp/audio and UI should be displaying right now BOOL systemFault; // a system fault is active? @@ -129,24 +141,33 @@ SW_FAULT_ID_ALARM_MGMT_LAMP_INVALID_ALARM_STATE, SW_FAULT_ID_COMM_BUFFERS_ADD_TOO_MUCH_DATA, SW_FAULT_ID_COMM_BUFFERS_ADD_INVALID_BUFFER, - SW_FAULT_ID_COMM_BUFFERS_GET_TOO_MUCH_DATA, // 20 - SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, - SW_FAULT_ID_COMM_BUFFERS_PEEK_TOO_MUCH_DATA, + SW_FAULT_ID_COMM_BUFFERS_GET_INVALID_BUFFER, // 20 SW_FAULT_ID_COMM_BUFFERS_PEEK_INVALID_BUFFER, SW_FAULT_ID_COMM_BUFFERS_COUNT_INVALID_BUFFER, - SW_FAULT_ID_FPGA_INVALID_IN_STATE, // 25 + SW_FAULT_ID_FPGA_INVALID_IN_STATE, SW_FAULT_ID_FPGA_INVALID_OUT_STATE, - SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, + SW_FAULT_ID_FPGA_WRITE_CMD_TOO_MUCH_DATA, // 25 SW_FAULT_ID_FPGA_WRITE_RSP_TOO_MUCH_DATA, SW_FAULT_ID_FPGA_READ_CMD_TOO_MUCH_DATA, - SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, // 30 + SW_FAULT_ID_FPGA_READ_RSP_TOO_MUCH_DATA, SW_FAULT_ID_MSG_QUEUES_ADD_QUEUE_FULL, - SW_FAULT_ID_MSG_QUEUES_ADD_INVALID_QUEUE, + SW_FAULT_ID_MSG_QUEUES_ADD_INVALID_QUEUE, // 30 SW_FAULT_ID_MSG_QUEUES_GET_INVALID_QUEUE, SW_FAULT_ID_MSG_QUEUES_IS_EMPTY_INVALID_QUEUE, - SW_FAULT_ID_MSG_QUEUES_IS_FULL_INVALID_QUEUE, // 35 + SW_FAULT_ID_MSG_QUEUES_IS_FULL_INVALID_QUEUE, SW_FAULT_ID_WATCHDOG_INVALID_SELF_TEST_STATE, - SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, + SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, // 35 + SW_FAULT_ID_DIAL_IN_FLOW_INVALID_DIAL_IN_PUMP_DIRECTION, + SW_FAULT_ID_DIAL_IN_FLOW_INVALID_DIAL_IN_PUMP_STATE, + SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, + SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_DIRECTION, + SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_STATE, // 40 + SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, + SW_FAULT_ID_BLOOD_FLOW_INVALID_FILTER_STATE, + SW_FAULT_ID_DIAL_IN_FLOW_INVALID_FILTER_STATE, + SW_FAULT_ID_RTC_EXEC_INVALID_STATE, + SW_FAULT_ID_RTC_SELF_TEST_INVALID_STATE, // 45 + SW_FAULT_ID_RTC_TRANSACTION_SERVICE_INVALID_STATE, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/CommBuffers.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/CommBuffers.c (.../CommBuffers.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -32,9 +32,10 @@ // ********** private data ********** -static U32 commBufferByteCount[ NUM_OF_COMM_BUFFERS ][ DOUBLE_BUFFERS ]; // for each buffer, how many bytes does it contain? (also index to next available) -static U32 activeDoubleBuffer[ NUM_OF_COMM_BUFFERS ]; // for each buffer, which double buffer is being fed right now? +static volatile U32 commBufferByteCount[ NUM_OF_COMM_BUFFERS ][ DOUBLE_BUFFERS ]; // for each buffer, how many bytes does it contain? (also index to next available) +static volatile U32 activeDoubleBuffer[ NUM_OF_COMM_BUFFERS ]; // for each buffer, which double buffer is being fed right now? static U08 commBuffers[ NUM_OF_COMM_BUFFERS ][ DOUBLE_BUFFERS ][ COMM_BUFFER_LENGTH ]; // each is double buffered to avoid thread contention +static volatile BOOL bufferGetLock[ NUM_OF_COMM_BUFFERS ]; // prevent getter from accessing active buffer while add in progress // ********** private function prototypes ********** @@ -96,6 +97,7 @@ // add requires brief thread protection because there may be multiple sources for transmits trying to add data to a buffer. _disable_IRQ(); + bufferGetLock[ buffer ] = TRUE; activeBuffer = activeDoubleBuffer[ buffer ]; currentActiveBufCount = commBufferByteCount[ buffer ][ activeBuffer ]; @@ -105,20 +107,22 @@ { U08 *buffPtr; // buffer destination for added data - // adjust buffer count per this data add (also reserves space to add data before releasing thread protection) - commBufferByteCount[ buffer ][ activeBuffer ] += len; - // release thread protection - _enable_IRQ(); // set destination pointer to end of active buffer data buffPtr = &commBuffers[ buffer ][ activeBuffer ][ currentActiveBufCount ]; // copy source data to destination buffer memcpy( buffPtr, data, len ); + // adjust buffer count per this data add (also reserves space to add data before releasing thread protection) + commBufferByteCount[ buffer ][ activeBuffer ] += len; + // release thread protection + bufferGetLock[ buffer ] = FALSE; + _enable_IRQ(); // data successfully added to buffer result = TRUE; } else // buffer too full to add this much data { // release thread protection + bufferGetLock[ buffer ] = FALSE; _enable_IRQ(); SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_ADD_TOO_MUCH_DATA, len ) } @@ -156,7 +160,7 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { - // verify size of get + // verify requested # of bytes to get are in the buffer if ( ( len <= ( COMM_BUFFER_LENGTH * DOUBLE_BUFFERS ) ) && ( len <= numberOfBytesInCommBuffer( buffer ) ) ) { U32 activeBuffer = activeDoubleBuffer[ buffer ]; @@ -179,10 +183,6 @@ result += remNumOfBytes; } } - else // invalid get size given - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_GET_TOO_MUCH_DATA, len ) - } } else // invalid buffer given { @@ -215,7 +215,7 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { - // verify size of peek + // verify requested # of bytes to peek are in the buffer if ( ( len <= ( COMM_BUFFER_LENGTH * DOUBLE_BUFFERS ) ) && ( len <= numberOfBytesInCommBuffer( buffer ) ) ) { U32 activeBuffer = activeDoubleBuffer[ buffer ]; @@ -237,10 +237,6 @@ numOfBytesPeeked = bytesInInactiveBuffer + remNumOfBytes; } } - else // invalid peek size given - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_COMM_BUFFERS_PEEK_TOO_MUCH_DATA, len ) - } } else // invalid buffer given { @@ -268,7 +264,17 @@ // verify given buffer if ( buffer < NUM_OF_COMM_BUFFERS ) { - result = commBufferByteCount[ buffer ][ 0 ] + commBufferByteCount[ buffer ][ 1 ]; + U32 activeBuffer = activeDoubleBuffer[ buffer ]; + U32 inactiveBuffer = GET_TOGGLE( activeBuffer, 0, 1 ); + + if ( FALSE == bufferGetLock[ buffer ] ) + { + result = commBufferByteCount[ buffer ][ inactiveBuffer ] + commBufferByteCount[ buffer ][ activeBuffer ]; + } + else + { + result = commBufferByteCount[ buffer ][ inactiveBuffer ]; + } } else // invalid buffer { Index: firmware/App/Services/FPGA.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -80,24 +80,32 @@ typedef struct // TODO - add all sensor readings to this structure per FPGA register map { - U08 bloodFlowMeterCommStatus; - U08 bloodFlowMeterFrameCount; - U16 bloodFlowMeterDeviceStatus; + U08 bloodFlowMeterDataPktCount; + U08 bloodFlowMeterSlowPktCounts; + U08 bloodFlowMeterDeviceStatus; + U08 bloodFlowMeterResponse; F32 bloodFlowLast; - F32 bloodFlowAvg; - F32 bloodFlowMeterSoundSpeed; - F32 bloodFlowMeterAccFlowData; - F32 bloodFlowMeterSignalStrength; - U32 bloodFlowMeterSensorID; - U08 dialysateFlowMeterCommStatus; - U08 dialysateFlowMeterFrameCount; - U16 dialysateFlowMeterDeviceStatus; + U08 dialysateFlowMeterDataPktCount; + U08 dialysateFlowMeterSlowPckCounts; + U08 dialysateFlowMeterDeviceStatus; + U08 dialysateFlowMeterResponse; F32 dialysateFlowLast; - F32 dialysateFlowAvg; - F32 dialysateFlowMeterSoundSpeed; - F32 dialysateFlowMeterAccFlowData; - F32 dialysateFlowMeterSignalStrength; - U32 dialysateFlowMeterSensorID; + U08 bloodFlowMeterErrorCount; + U08 dialysateFlowMeterErrorCount; + U16 bloodOcclusionData; + U08 bloodOcclusionReadCount; + U08 bloodOcclusionErrorCount; + U16 dialysateInOcclusionData; + U08 dialysateInOcclusionReadCount; + U08 dialysateInOcclusionErrorCount; + U16 dialysateOutOcclusionData; + U08 dialysateOutOcclusionReadCount; + U08 dialysateOutOcclusionErrorCount; + U16 arterialPressureData; + U08 arterialPressureReadCount; + U08 arterialPressureErrorCount; + U16 dialysateTempPrimaryData; + U16 dialysateTempBackupData; } FPGA_SENSORS_T; typedef struct // TODO - add all actuator set points to this structure per FPGA register map @@ -920,7 +928,7 @@ // clear any errors sciRxError( scilinREG ); // if a byte is pending read, read it - if ( 0 != sciIsRxReady( scilinREG ) ) + if ( sciIsRxReady( scilinREG ) != 0 ) { sciReceiveByte( scilinREG ); } Index: firmware/App/Services/Interrupts.c =================================================================== diff -u -r6311eb9b65fdeec7a285d25e07f3932ac0fb6cf1 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision 6311eb9b65fdeec7a285d25e07f3932ac0fb6cf1) +++ firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -26,6 +26,7 @@ #include "Comm.h" #include "Interrupts.h" #include "MsgQueues.h" +#include "Utilities.h" #include "SystemCommMessages.h" #ifdef RM46_EVAL_BOARD_TARGET @@ -71,9 +72,9 @@ static g_dmaCTRL pcDMAXmitControlRecord; // DMA transmit control record (UART-debug) static g_dmaCTRL pcDMARecvControlRecord; // DMA receive control record (UART-debug) -static BOOL dgIsCommunicating = FALSE; // has DG sent a message since last check -static BOOL uiIsCommunicating = FALSE; // has UI sent a message since last check -static BOOL uiDidCommunicate = FALSE; // has UI every sent a message +static volatile BOOL dgIsCommunicating = FALSE; // has DG sent a message since last check +static volatile BOOL uiIsCommunicating = FALSE; // has UI sent a message since last check +static volatile BOOL uiDidCommunicate = FALSE; // has UI every sent a message // ********** private function prototypes ********** @@ -222,23 +223,13 @@ // if CAN transmitter is idle, start transmitting any pending packets if ( FALSE == isCAN1TransmitInProgress() ) { - U32 bytesXmitted = transmitNextCANPacket(); - - if ( bytesXmitted > 0 ) - { - signalCANXmitsInitiated(); - } + transmitNextCANPacket(); } // if UART transmitter is idle, start transmitting any pending packets if ( FALSE == isSCI1DMATransmitInProgress() ) { - U32 bytesXmitted = transmitNextUARTPacket(); - - if ( bytesXmitted > 0 ) - { - signalSCI1XmitsInitiated(); - } + transmitNextUARTPacket(); } } @@ -503,9 +494,22 @@ // if there's another CAN packet to send, send it if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) { - canTransmit( canREG1, mBox, data ); - result = CAN_MESSAGE_PAYLOAD_SIZE; + signalCANXmitsInitiated(); + if ( 0 != canTransmit( canREG1, mBox, data ) ) + { + result = CAN_MESSAGE_PAYLOAD_SIZE; + } + else + { + signalCANXmitsCompleted(); + // TODO - shouldn't get here, but let's see if we do + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_SOFTWARE_FAULT, (U32)mBox ) + } } + else + { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) + } } return result; @@ -534,6 +538,7 @@ // if there's another UART packet to send, send it if ( dataSize == PC_MESSAGE_PACKET_SIZE ) { + signalSCI1XmitsInitiated(); dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); dmaSetChEnable( DMA_CH3, DMA_HW ); setSCI1DMATransmitInterrupt(); @@ -714,7 +719,7 @@ if ( TRUE == isThereMsgRcvd ) { // TODO - check CRC before processing a message - if ( 1 ) + if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) { processReceivedMessage( &message.msg ); } @@ -810,12 +815,12 @@ handleTestBloodFlowMeasuredOverrideRequest( message ); break; - case MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE: - handleTestBloodPumpMeasuredSpeedOverrideRequest( message ); + case MSG_ID_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE: + handleTestBloodPumpMCMeasuredSpeedOverrideRequest( message ); break; - case MSG_ID_BLOOD_PUMP_MEAS_CURR_OVERRIDE: - handleTestBloodPumpMeasuredCurrentOverrideRequest( message ); + case MSG_ID_BLOOD_PUMP_MC_MEAS_CURR_OVERRIDE: + handleTestBloodPumpMCMeasuredCurrentOverrideRequest( message ); break; case MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE: @@ -826,6 +831,42 @@ handleTestAlarmStatusBroadcastIntervalOverrideRequest( message ); break; + case MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE: + handleTestBloodPumpMeasuredSpeedOverrideRequest( message ); + break; + + case MSG_ID_BLOOD_PUMP_MEAS_ROTOR_SPEED_OVERRIDE: + handleTestBloodPumpRotorMeasuredSpeedOverrideRequest( message ); + break; + + case MSG_ID_DIAL_FLOW_SET_PT_OVERRIDE: + handleTestDialFlowSetPointOverrideRequest( message ); + break; + + case MSG_ID_DIAL_FLOW_MEAS_OVERRIDE: + handleTestDialFlowMeasuredOverrideRequest( message ); + break; + + case MSG_ID_DIAL_PUMP_MC_MEAS_SPEED_OVERRIDE: + handleTestDialPumpMCMeasuredSpeedOverrideRequest( message ); + break; + + case MSG_ID_DIAL_PUMP_MC_MEAS_CURR_OVERRIDE: + handleTestDialPumpMCMeasuredCurrentOverrideRequest( message ); + break; + + case MSG_ID_DIAL_FLOW_SEND_INTERVAL_OVERRIDE: + handleTestDialFlowBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_DIAL_PUMP_MEAS_SPEED_OVERRIDE: + handleTestDialPumpMeasuredSpeedOverrideRequest( message ); + break; + + case MSG_ID_DIAL_PUMP_MEAS_ROTOR_SPEED_OVERRIDE: + handleTestDialPumpRotorMeasuredSpeedOverrideRequest( message ); + break; + default: // TODO - unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r8f8776e48894e31cba816ebef2edf96d14306ba8 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 8f8776e48894e31cba816ebef2edf96d14306ba8) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -32,24 +32,34 @@ MSG_ID_BLOOD_FLOW_DATA, // 5 MSG_ID_DG_CHECK_IN, // 6 MSG_ID_UI_CHECK_IN, // 7 + MSG_ID_DIALYSATE_FLOW_DATA, // 8 // service/test CAN messages - MSG_ID_FIRST_TESTER_MESSAGE = 0x8000, // 0x8000 + MSG_ID_FIRST_TESTER_MESSAGE = 0x8000, // 0x8000 MSG_ID_TESTER_LOGIN_REQUEST = MSG_ID_FIRST_TESTER_MESSAGE, - MSG_ID_HD_MESSAGE, // 0x8001 - MSG_ID_OFF_BUTTON_STATE_OVERRIDE, // 0x8002 - MSG_ID_STOP_BUTTON_STATE_OVERRIDE, // 0x8003 - MSG_ID_ALARM_LAMP_PATTERN_OVERRIDE, // 0x8004 - MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE, // 0x8005 - MSG_ID_ALARM_STATE_OVERRIDE, // 0x8006 - MSG_ID_ALARM_TIME_OVERRIDE, // 0x8007 - MSG_ID_BLOOD_FLOW_SET_PT_OVERRIDE, // 0x8008 - MSG_ID_BLOOD_FLOW_MEAS_OVERRIDE, // 0x8009 - MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE, // 0x800A - MSG_ID_BLOOD_PUMP_MEAS_CURR_OVERRIDE, // 0x800B - MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE, // 0x800C - MSG_ID_ALARM_STATUS_SEND_INTERVAL_OVERRIDE, // 0x800D + MSG_ID_HD_MESSAGE, // 0x8001 + MSG_ID_OFF_BUTTON_STATE_OVERRIDE, // 0x8002 + MSG_ID_STOP_BUTTON_STATE_OVERRIDE, // 0x8003 + MSG_ID_ALARM_LAMP_PATTERN_OVERRIDE, // 0x8004 + MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE, // 0x8005 + MSG_ID_ALARM_STATE_OVERRIDE, // 0x8006 + MSG_ID_ALARM_TIME_OVERRIDE, // 0x8007 + MSG_ID_BLOOD_FLOW_SET_PT_OVERRIDE, // 0x8008 + MSG_ID_BLOOD_FLOW_MEAS_OVERRIDE, // 0x8009 + MSG_ID_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE, // 0x800A + MSG_ID_BLOOD_PUMP_MC_MEAS_CURR_OVERRIDE, // 0x800B + MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE, // 0x800C + MSG_ID_ALARM_STATUS_SEND_INTERVAL_OVERRIDE, // 0x800D + MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE, // 0x800E + MSG_ID_BLOOD_PUMP_MEAS_ROTOR_SPEED_OVERRIDE, // 0x800F + MSG_ID_DIAL_FLOW_SET_PT_OVERRIDE, // 0x8010 + MSG_ID_DIAL_FLOW_MEAS_OVERRIDE, // 0x8011 + MSG_ID_DIAL_PUMP_MC_MEAS_SPEED_OVERRIDE, // 0x8012 + MSG_ID_DIAL_PUMP_MC_MEAS_CURR_OVERRIDE, // 0x8013 + MSG_ID_DIAL_FLOW_SEND_INTERVAL_OVERRIDE, // 0x8014 + MSG_ID_DIAL_PUMP_MEAS_SPEED_OVERRIDE, // 0x8015 + MSG_ID_DIAL_PUMP_MEAS_ROTOR_SPEED_OVERRIDE, // 0x8016 END_OF_MSG_IDS } MSG_ID_T; @@ -62,13 +72,16 @@ // MSG_ID_ALARM_STATUS BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); // MSG_ID_ALARM_TRIGGERED -BOOL broadcastAlarmTriggered( ALARM_ID_T alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); +BOOL broadcastAlarmTriggered( U16 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); // MSG_ID_ALARM_CLEARED -BOOL broadcastAlarmCleared( ALARM_ID_T alarm ); +BOOL broadcastAlarmCleared( U16 alarm ); // MSG_ID_BLOOD_FLOW_DATA -BOOL broadcastBloodFlowData( U32 flowStPt, F32 measFlow, F32 measRotorSpd, F32 measSpd, F32 measMCSpd, F32 measMCCurr ); +BOOL broadcastBloodFlowData( U32 flowStPt, F32 measFlow, F32 measRotorSpd, F32 measSpd, F32 measMCSpd, F32 measMCCurr, F32 pwmDC ); +// MSG_ID_DIALYSATE_FLOW_DATA +BOOL broadcastDialInFlowData( U32 flowStPt, F32 measFlow, F32 measRotorSpd, F32 measSpd, F32 measMCSpd, F32 measMCCurr, F32 pwmDC ); + // MSG_ID_DG_CHECK_IN void handleDGCheckIn( MESSAGE_T *message ); // MSG_ID_UI_CHECK_IN @@ -113,13 +126,41 @@ // MSG_ID_BLOOD_FLOW_MEAS_OVERRIDE void handleTestBloodFlowMeasuredOverrideRequest( MESSAGE_T *message ); -// MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE -void handleTestBloodPumpMeasuredSpeedOverrideRequest( MESSAGE_T *message ); +// MSG_ID_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE +void handleTestBloodPumpMCMeasuredSpeedOverrideRequest( MESSAGE_T *message ); -// MSG_ID_BLOOD_PUMP_MEAS_CURR_OVERRIDE -void handleTestBloodPumpMeasuredCurrentOverrideRequest( MESSAGE_T *message ); +// MSG_ID_BLOOD_PUMP_MC_MEAS_CURR_OVERRIDE +void handleTestBloodPumpMCMeasuredCurrentOverrideRequest( MESSAGE_T *message ); // MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE void handleTestBloodFlowBroadcastIntervalOverrideRequest( MESSAGE_T *message ); +// MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE +void handleTestBloodPumpMeasuredSpeedOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_BLOOD_PUMP_MEAS_ROTOR_SPEED_OVERRIDE +void handleTestBloodPumpRotorMeasuredSpeedOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_FLOW_SET_PT_OVERRIDE +void handleTestDialFlowSetPointOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_FLOW_MEAS_OVERRIDE +void handleTestDialFlowMeasuredOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_PUMP_MC_MEAS_SPEED_OVERRIDE +void handleTestDialPumpMCMeasuredSpeedOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_PUMP_MC_MEAS_CURR_OVERRIDE +void handleTestDialPumpMCMeasuredCurrentOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_FLOW_SEND_INTERVAL_OVERRIDE +void handleTestDialFlowBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_PUMP_MEAS_SPEED_OVERRIDE +void handleTestDialPumpMeasuredSpeedOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DIAL_PUMP_MEAS_ROTOR_SPEED_OVERRIDE +void handleTestDialPumpRotorMeasuredSpeedOverrideRequest( MESSAGE_T *message ); + + #endif Index: firmware/App/Services/Utilities.c =================================================================== diff -u -rd71d1e6c2be627158cac9a8bc56adac7cdefd1c8 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/Utilities.c (.../Utilities.c) (revision d71d1e6c2be627158cac9a8bc56adac7cdefd1c8) +++ firmware/App/Services/Utilities.c (.../Utilities.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * 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. Index: firmware/App/Services/WatchdogMgmt.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -16,31 +16,34 @@ #include "Common.h" #include "CPLD.h" +#include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "Timers.h" #include "WatchdogMgmt.h" // ********** private definitions ********** #define MIN_WATCHDOG_PET_INTERVAL_MS 45 +#define WATCHDOG_POST_TIMEOUT_MS 100 +#define WATCHDOG_RECOVERY_TIME_MS 250 typedef enum Button_Self_Test_States { WATCHDOG_SELF_TEST_STATE_START = 0, WATCHDOG_SELF_TEST_STATE_IN_PROGRESS, + WATCHDOG_SELF_TEST_STATE_RECOVER, WATCHDOG_SELF_TEST_STATE_COMPLETE, NUM_OF_WATCHDOG_SELF_TEST_STATES } WATCHDOG_SELF_TEST_STATE_T; -#define WATCHDOG_POST_TIMEOUT_MS 100 // ms - // ********** private data ********** static U32 lastWatchdogPetTime = 0; DATA_ARRAY_DECL( BOOL, TaskCheckIns, NUM_OF_TASKS, watchdogTaskCheckedIn ); static WATCHDOG_SELF_TEST_STATE_T watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_START; +static SELF_TEST_STATUS_T watchdogSelfTestStatus; static U32 watchdogSelfTestTimerCount = 0; // ********** private function prototypes ********** @@ -65,6 +68,7 @@ lastWatchdogPetTime = 0; watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_START; + watchdogSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; watchdogSelfTestTimerCount = 0; // initialize task check-ins to false for ( i = 0; i < NUM_OF_TASKS; i++ ) @@ -105,7 +109,14 @@ // check to see if watchdog has expired if ( getCPLDWatchdogExpired() == PIN_SIGNAL_HIGH ) { - // TODO - watchdog expired fault + // ignore expired watchdog until after watchdog POST + if ( WATCHDOG_SELF_TEST_STATE_COMPLETE == watchdogSelfTestState ) + { +#ifndef DEBUG_ENABLED + activateSafetyShutdown(); // TODO - restore these - commented out now so that we don't get WD error with breakpoints while debugging + activateAlarmNoData( ALARM_ID_WATCHDOG_EXPIRED ); +#endif + } } } @@ -156,18 +167,28 @@ } if ( getCPLDWatchdogExpired() == PIN_SIGNAL_HIGH ) { - result = SELF_TEST_STATUS_PASSED; + watchdogSelfTestStatus = SELF_TEST_STATUS_PASSED; } else { activateAlarmNoData( ALARM_ID_WATCHDOG_POST_TEST_FAILED ); - result = SELF_TEST_STATUS_FAILED; + watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } - watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_COMPLETE; + watchdogSelfTestTimerCount = getMSTimerCount(); + watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_RECOVER; break; + case WATCHDOG_SELF_TEST_STATE_RECOVER: + if ( TRUE == didTimeout( watchdogSelfTestTimerCount, WATCHDOG_RECOVERY_TIME_MS ) ) + { + result = watchdogSelfTestStatus; + watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_COMPLETE; + } + break; + case WATCHDOG_SELF_TEST_STATE_COMPLETE: // if we get called in this state, assume we're doing self test again + watchdogSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; watchdogSelfTestState = WATCHDOG_SELF_TEST_STATE_START; break; Index: firmware/App/Tasks/TaskBG.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Tasks/TaskBG.c (.../TaskBG.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Tasks/TaskBG.c (.../TaskBG.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -57,8 +57,6 @@ if ( TRUE == didTimeout( startUICommTimeout, MAX_TIME_FOR_UI_TO_COMMUNICATE_MS ) ) { activateAlarmNoData( ALARM_ID_UI_COMM_POST_FAILED ); - activateSafetyShutdown(); // TODO - for now, possibly remove later - //checkInFromUI(); // pretend we got something from UI to unlock task processing of HD } } } Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -19,6 +19,7 @@ #include "Common.h" #include "AlarmLamp.h" #include "BloodFlow.h" +#include "DialInFlow.h" #include "OperationModes.h" #include "SystemComm.h" #include "WatchdogMgmt.h" @@ -52,13 +53,18 @@ execSystemCommRx(); // prevent most processing until UI has started communicating +#ifndef RM46_EVAL_BOARD_TARGET if ( TRUE == uiCommunicated() ) +#endif { + // run operation mode state machine + execOperationModes(); + // control blood pump execBloodFlowController(); - // run operation mode state machine - execOperationModes(); + // control dialysate inlet pump + execDialInFlowController(); // manage alarm state execAlarmMgmt(); Index: firmware/App/Tasks/TaskPriority.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 --- firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) @@ -19,6 +19,7 @@ #include "InternalADC.h" #include "BloodFlow.h" #include "Buttons.h" +#include "DialInFlow.h" #include "FPGA.h" #include "SystemComm.h" #include "WatchdogMgmt.h" @@ -35,7 +36,9 @@ void taskPriority( void ) { // prevent most processing until UI has started communicating +#ifndef RM46_EVAL_BOARD_TARGET if ( TRUE == uiCommunicated() ) +#endif { // 1st pass for FPGA execFPGAIn(); @@ -49,6 +52,9 @@ // monitor blood pump and flow execBloodFlowMonitor(); + // monitor dialysate inlet pump and flow + execDialInFlowMonitor(); + // 2nd pass for FPGA execFPGAOut();