Index: firmware/App/Common.h =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Common.h (.../Common.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Common.h (.../Common.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -23,6 +23,7 @@ #ifndef _VECTORCAST_ // #define RM46_EVAL_BOARD_TARGET 1 + #define ACK_IMPLEMENTED 1 // #define SIMULATE_UI 1 #define DEBUG_ENABLED 1 @@ -95,8 +96,8 @@ #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 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)) Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -43,9 +43,9 @@ #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_P_COEFFICIENT 0.0002 // P term for blood pump control -#define BP_I_COEFFICIENT 0.00002 // I term for blood pump control +#define BP_CONTROL_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) // interval (ms/task time) at which the blood pump is controlled +#define BP_P_COEFFICIENT 0.00005 // P term for blood pump control +#define BP_I_COEFFICIENT 0.00015 // I term for blood pump control #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 @@ -60,7 +60,7 @@ #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.0003717 // ~27 BP motor RPM = 1% PWM duty cycle +#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00042 // ~24 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 ) @@ -69,7 +69,7 @@ #define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_MID_PT_BITS ) #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 SIZE_OF_ROLLING_AVG ( BLOOD_FLOW_SAMPLE_FREQ * 2 ) // 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 @@ -624,10 +624,11 @@ F32 pumpPWMPctDutyCycle = bloodPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; #ifdef DEBUG_ENABLED // TODO - temporary debug code - remove later - char debugFlowStr[ 256 ]; + F32 x = getFPGADialysateInletOcclusion(); +// char debugFlowStr[ 256 ]; - 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) ); +// 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, pumpPWMPctDutyCycle ); bloodFlowDataPublicationTimerCounter = 0; @@ -725,6 +726,22 @@ } flowReadingsTmrCtr = INC_WRAP( flowReadingsTmrCtr, 0, MAX_FLOW_FILTER_INTERVAL - 1 ); +#ifdef DEBUG_ENABLED + { + // TODO - temporary debug code - remove later +// char debugFlowStr[ 40 ]; + //S32 num = (S32)(flow); + //S32 dec = (S32)(fabs(flow-(S32)(flow))*100.0); +// S32 numf = (S32)(measuredBloodFlowRate.data); +// S32 decf = (S32)(fabs(measuredBloodFlowRate.data-(S32)(measuredBloodFlowRate.data))*100.0); +// S32 nump = (S32)bloodPumpPWMDutyCyclePctSet; +// S32 decp = (S32)((bloodPumpPWMDutyCyclePctSet-(S32)bloodPumpPWMDutyCyclePctSet)*100.0); + +// sprintf( debugFlowStr, "%5d.%02d %5d.%02d\n", numf, decf, numf, decf ); +// sprintf( debugFlowStr, "%5d.%02d %5d.%02d\n", num, dec, numf, decf ); +// sendDebugData( (U08*)debugFlowStr, strlen(debugFlowStr) ); + } +#endif } /************************************************************************* Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r832ca83805dc132cb753e79bdca81197331e03e6 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 832ca83805dc132cb753e79bdca81197331e03e6) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -44,9 +44,9 @@ #define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.88 // controller will error if PWM duty cycle > 90%, so set max to 88% #define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.12 // controller will error if PWM duty cycle < 10%, so set min to 12% -#define DIP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) // interval (ms/task time) at which the dialIn pump is controlled -#define DIP_P_COEFFICIENT 0.0002 // P term for dialIn pump control -#define DIP_I_COEFFICIENT 0.00002 // I term for dialIn pump control +#define DIP_CONTROL_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) // interval (ms/task time) at which the dialIn pump is controlled +#define DIP_P_COEFFICIENT 0.00005 // P term for dialIn pump control +#define DIP_I_COEFFICIENT 0.00015 // I term for dialIn pump control #define DIP_MAX_PWM_DC_DELTA 0.01 // prevents large steps in PWM duty cycle #define DIP_MIN_PWM_DC_DELTA -0.01 @@ -61,7 +61,7 @@ #define DIP_REV_PER_LITER 124.0 // rotor revolutions per liter #define DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DIP_REV_PER_LITER / ML_PER_LITER ) #define DIP_GEAR_RATIO 32.0 // dialIn pump motor to dialIn pump gear ratio -#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003717 // ~27 BP motor RPM = 1% PWM duty cycle +#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00042 // ~24 BP motor RPM = 1% PWM duty cycle #define DIP_PWM_ZERO_OFFSET 0.1 // 10% PWM duty cycle = zero speed #define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) @@ -70,7 +70,7 @@ #define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DIAL_IN_PUMP_ADC_MID_PT_BITS ) #define DIAL_IN_FLOW_SAMPLE_FREQ ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) -#define SIZE_OF_ROLLING_AVG (U32)( (F32)DIAL_IN_FLOW_SAMPLE_FREQ * 0.8 ) // measured dialIn flow is filtered w/ moving average +#define SIZE_OF_ROLLING_AVG ( DIAL_IN_FLOW_SAMPLE_FREQ * 2 ) // measured dialIn flow is filtered w/ moving average #define MAX_FLOW_FILTER_INTERVAL 5 // slowest sample interval for filter is every 5th sample typedef enum DialInPump_States Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -29,6 +29,11 @@ #define ALARM_SILENCE_EXPIRES_IN_SECS (60) +#define ALM_ESC_1_MIN (1 * SEC_PER_MIN * MS_PER_SECOND) +#define ALM_ESC_4_MIN (4 * SEC_PER_MIN * MS_PER_SECOND) +#define ALM_ESC_5_MIN (5 * SEC_PER_MIN * MS_PER_SECOND) +#define ALM_ESC_10_MIN (10 * SEC_PER_MIN * MS_PER_SECOND) + #pragma pack(push,1) typedef struct { @@ -47,37 +52,48 @@ #pragma pack(pop) const ALARM_T alarmTable[ NUM_OF_ALARM_IDS ] = -{ // Priority Esc Escalate To Fault Stops NoClr NoRes NoRin NoEnd NoNew Bypass - { ALARM_PRIORITY_NONE, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NO_ALARM - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_SOFTWARE_FAULT - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_STUCK_BUTTON_TEST_FAILED - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_FPGA_POST_TEST_FAILED - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_WATCHDOG_POST_TEST_FAILED - { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_UI_COMM_POST_FAILED - { 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_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 +{ // Priority Esc Escalate To Fault Stops NoClr NoRes NoRin NoEnd NoNew Bypass + { ALARM_PRIORITY_NONE, 0, ALARM_ID_NO_ALARM, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_NO_ALARM + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_SOFTWARE_FAULT + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_STUCK_BUTTON_TEST_FAILED + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_FPGA_POST_TEST_FAILED + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_WATCHDOG_POST_TEST_FAILED + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_UI_COMM_POST_FAILED + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK + { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK + { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_SPEED_CHECK + { ALARM_PRIORITY_MEDIUM, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK + { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, 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 + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_RTC_COMM_ERROR + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_RTC_CONFIG_ERROR + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_DG_COMM_TIMEOUT + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, TRUE, TRUE , TRUE , TRUE , TRUE , TRUE , TRUE , FALSE }, // ALARM_ID_UI_COMM_TIMEOUT + { ALARM_PRIORITY_HIGH, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, TRUE, TRUE , TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, // ALARM_ID_COMM_TOO_MANY_BAD_CRCS + { ALARM_PRIORITY_LOW, ALM_ESC_4_MIN, ALARM_ID_BLOOD_SITTING_WARNING, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_TREATMENT_STOPPED_BY_USER + { ALARM_PRIORITY_MEDIUM, ALM_ESC_1_MIN, ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME, FALSE, TRUE , FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_WARNING + { ALARM_PRIORITY_MEDIUM, ALM_ESC_5_MIN, ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK, FALSE, TRUE , FALSE, TRUE, FALSE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME + { ALARM_PRIORITY_HIGH, 0, ALARM_ID_NO_ALARM, FALSE, TRUE , FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }, // ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK }; const ALARM_DATA_T blankAlarmData = { ALARM_DATA_TYPE_NONE, 0 }; // ********** private data ********** -static U32 alarmStatusPublicationTimerCounter = 0; // used to schedule alarm status publication to CAN bus // interval (in ms) at which to publish alarm status to CAN bus DATA_DECL( U32, AlarmStatusPub, alarmStatusPublishInterval, ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL ); +static U32 alarmStatusPublicationTimerCounter = 0; // used to schedule alarm status publication to CAN bus +// table - current state of each alarm DATA_ARRAY_DECL( BOOL, AlarmStates, NUM_OF_ALARM_IDS, alarmIsActive ); +// table - when alarm became active for each alarm (if active) or zero (if inactive) DATA_ARRAY_DECL( U32, AlarmStarts, NUM_OF_ALARM_IDS, alarmStartedAt ); static COMP_ALARM_STATUS_T alarmStatus; Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -42,6 +42,13 @@ ALARM_ID_WATCHDOG_EXPIRED, ALARM_ID_RTC_COMM_ERROR, ALARM_ID_RTC_CONFIG_ERROR, // 20 + ALARM_ID_DG_COMM_TIMEOUT, + ALARM_ID_UI_COMM_TIMEOUT, + ALARM_ID_COMM_TOO_MANY_BAD_CRCS, + ALARM_ID_TREATMENT_STOPPED_BY_USER, + ALARM_ID_BLOOD_SITTING_WARNING, // 25 + ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME, + ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK, NUM_OF_ALARM_IDS } ALARM_ID_T; Index: firmware/App/Services/FPGA.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -914,6 +914,76 @@ } /************************************************************************* + * @brief getFPGABloodOcclusion + * The getFPGABloodOcclusion function gets the latest blood occlusion reading. + * @details + * Inputs : fpgaSensorReadings + * Outputs : none + * @param none + * @return last blood occlusion reading + *************************************************************************/ +F32 getFPGABloodOcclusion( void ) +{ + return fpgaSensorReadings.bloodOcclusionData; +} + +/************************************************************************* + * @brief getFPGADialysateInletOcclusion + * The getFPGADialysateInletOcclusion function gets the latest dialysate \n + * inlet occlusion reading. + * @details + * Inputs : fpgaSensorReadings + * Outputs : none + * @param none + * @return last dialysate inlet occlusion reading + *************************************************************************/ +F32 getFPGADialysateInletOcclusion( void ) +{ +#ifdef DEBUG_ENABLED + { + // TODO - temporary debug code - remove later + char debugOccStr[ 60 ]; + S32 dat = fpgaSensorReadings.dialysateInOcclusionData; + S32 rct = fpgaSensorReadings.dialysateInOcclusionReadCount; + S32 ect = fpgaSensorReadings.dialysateInOcclusionErrorCount; + + sprintf( debugOccStr, "Data %5d Reads %5d Errors %5d\n", dat, rct, ect ); + sendDebugData( (U08*)debugOccStr, strlen(debugOccStr) ); + } +#endif + return fpgaSensorReadings.dialysateInOcclusionData; +} + +/************************************************************************* + * @brief getFPGADialysateOutletOcclusion + * The getFPGADialysateOutletOcclusion function gets the latest dialysate \n + * outlet occlusion reading. + * @details + * Inputs : fpgaSensorReadings + * Outputs : none + * @param none + * @return last dialysate outlet occlusion reading + *************************************************************************/ +F32 getFPGADialysateOutletOcclusion( void ) +{ + return fpgaSensorReadings.dialysateOutOcclusionData; +} + +/************************************************************************* + * @brief getFPGAArterialPressure + * The getFPGAArterialPressure function gets the latest arterial pressure reading. + * @details + * Inputs : fpgaSensorReadings + * Outputs : none + * @param none + * @return last arterial pressure reading + *************************************************************************/ +F32 getFPGAArterialPressure( void ) +{ + return fpgaSensorReadings.arterialPressureData; +} + +/************************************************************************* * @brief consumeUnexpectedData * The consumeUnexpectedData function checks to see if a byte is sitting in \n * the SCI2 received data register. Index: firmware/App/Services/FPGA.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -36,5 +36,9 @@ void setFPGAControl( U16 ctrl ); F32 getFPGABloodFlow( void ); F32 getFPGADialysateFlow( void ); +F32 getFPGABloodOcclusion( void ); +F32 getFPGADialysateInletOcclusion( void ); +F32 getFPGADialysateOutletOcclusion( void ); +F32 getFPGAArterialPressure( void ); #endif Index: firmware/App/Services/MsgQueues.c =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/MsgQueues.c (.../MsgQueues.c) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/MsgQueues.c (.../MsgQueues.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -220,9 +220,6 @@ { *msgContent++ = 0x0; } - - // set msg ID out of bounds in case blank message goes somewhere - message->hdr.msgID = 0xFFFF; } /************************************************************************* Index: firmware/App/Services/MsgQueues.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/MsgQueues.h (.../MsgQueues.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/MsgQueues.h (.../MsgQueues.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -32,6 +32,9 @@ #pragma pack(push,1) typedef struct { +#ifdef ACK_IMPLEMENTED + U16 seqNo; // sequence # (and ACK required bit) of message +#endif U16 msgID; // ID of message U08 payloadLen; // length of payload in bytes } MESSAGE_HEADER_T; Index: firmware/App/Services/PIControllers.c =================================================================== diff -u -r832ca83805dc132cb753e79bdca81197331e03e6 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 832ca83805dc132cb753e79bdca81197331e03e6) +++ firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -15,8 +15,11 @@ * **************************************************************************/ -#include "math.h" +#ifndef _VECTORCAST_ + #include "math.h" +#endif +#include "SystemCommMessages.h" #include "PIControllers.h" // ********** private definitions ********** @@ -144,12 +147,29 @@ controlSignalBeforeWindup = ( controller->Kp * controller->errorSignal ) + ( controller->Ki * controller->errorSum ); controller->controlSignal = RANGE( controlSignalBeforeWindup, controller->uMin, controller->uMax ); // handle anti-windup for i term - windupError = controller->controlSignal - controlSignalBeforeWindup; + windupError = controlSignalBeforeWindup - controller->controlSignal; if ( fabs( windupError ) > NEARLY_ZERO ) { controller->errorSum -= ( windupError / controller->Ki ); } result = controller->controlSignal; +//#ifdef DEBUG_ENABLED +// { +// // TODO - temporary debug code - remove later +// char debugFlowStr[ 100 ]; +// S32 nums = (S32)(measuredSignal); +// S32 decs = (S32)(fabs(measuredSignal-(S32)(measuredSignal))*100.0); +// S32 nume = (S32)controller->errorSignal; +// S32 dece = (S32)(fabs(controller->errorSignal-(S32)controller->errorSignal)*100.0); +// S32 numes = (S32)controller->errorSum; +// S32 deces = (S32)((controller->errorSum-(S32)(controller->errorSum))*100.0); +// S32 nump = (S32)controller->controlSignal; +// S32 decp = (S32)((controller->controlSignal-(S32)controller->controlSignal)*10000.0); +// +// sprintf( debugFlowStr, "%6d.%02d %6d.%02d %10d.%02d %3d.%04d\n", nums, decs, nume, dece, numes, deces, nump, decp ); +// sendDebugData( (U08*)debugFlowStr, strlen(debugFlowStr) ); +// } +//#endif } return result; Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -25,7 +25,7 @@ #include "SystemComm.h" #include "Comm.h" #include "Interrupts.h" -#include "MsgQueues.h" +#include "Timers.h" #include "Utilities.h" #include "SystemCommMessages.h" @@ -42,6 +42,31 @@ #define SCI1_RECEIVE_DMA_REQUEST 30 #define SCI1_TRANSMIT_DMA_REQUEST 31 +#define UI_COMM_TIMEOUT_IN_MS 5000 +#define DG_COMM_TIMEOUT_IN_MS 2000 + +#define MAX_COMM_CRC_FAILURES 5 +#define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) + +#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) +#define MSG_NOT_ACKED_MAX_RETRIES 5 +#define PENDING_ACK_LIST_SIZE 25 + +#pragma pack(push,1) + +typedef struct +{ + BOOL used; + U16 seqNo; + U16 retries; + U32 timeStamp; + COMM_BUFFER_T channel; + U32 msgSize; + U08 msg[ MAX_ACK_MSG_SIZE ]; +} PENDING_ACK_RECORD_T; + +#pragma pack(pop) + // ********** private data ********** const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = @@ -68,14 +93,22 @@ static U08 pcXmitPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static U08 pcRecvPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; // list of outgoing messages that are awaiting an ACK + // DMA control records -static g_dmaCTRL pcDMAXmitControlRecord; // DMA transmit control record (UART-debug) -static g_dmaCTRL pcDMARecvControlRecord; // DMA receive control record (UART-debug) +static g_dmaCTRL pcDMAXmitControlRecord; // DMA transmit control record (UART-debug) +static g_dmaCTRL pcDMARecvControlRecord; // DMA receive control record (UART-debug) -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 +static volatile BOOL dgIsCommunicating = FALSE; // has DG sent a message since last check +static U32 timeOfLastDGCheckIn = 0; // last time DG checked in +static volatile BOOL uiIsCommunicating = FALSE; // has UI sent a message since last check +static U32 timeOfLastUICheckIn = 0; // last time UI checked in +static volatile BOOL uiDidCommunicate = FALSE; // has UI every sent a message +static U32 badCRCTimeStamps[ MAX_COMM_CRC_FAILURES ]; // time of last five bad message CRCs (wrapping list) +static U32 badCRCListIdx = 0; // where next bad message CRC time stamp will go in list +static U32 badCRCListCount = 0; // # of bad CRCs in the list + // ********** private function prototypes ********** static void initUARTAndDMA( void ); @@ -92,6 +125,14 @@ static void processReceivedMessages( void ); static void processReceivedMessage( MESSAGE_T *message ); +static void checkForCommTimeouts( void ); +static void checkTooManyBadMsgCRCs( U16 msgID ); + +#ifdef ACK_IMPLEMENTED +static BOOL matchACKtoPendingACKList( U16 seqNo ); +static void checkPendingACKList( void ); +#endif + /************************************************************************* * @brief initSystemComm * The initSystemComm function initializes the SystemComm module. @@ -103,8 +144,22 @@ *************************************************************************/ void initSystemComm( void ) { + U32 i; + // initialize UART and DMA for PC communication initUARTAndDMA(); + + // initialize bad message CRC list + for ( i = 0; i < MAX_COMM_CRC_FAILURES; i++ ) + { + badCRCTimeStamps[ i ] = 0; + } + + // initialize pending ACK list + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + pendingAckList[ i ].used = FALSE; + } } /************************************************************************* @@ -120,6 +175,7 @@ void checkInFromDG( void ) { dgIsCommunicating = TRUE; + timeOfLastDGCheckIn = getMSTimerCount(); } /************************************************************************* @@ -135,6 +191,7 @@ void checkInFromUI( void ) { uiIsCommunicating = TRUE; + timeOfLastUICheckIn = getMSTimerCount(); uiDidCommunicate = TRUE; } @@ -206,6 +263,12 @@ // process received messages in the queue processReceivedMessages(); + + // check for sub-system comm timeouts + checkForCommTimeouts(); + + // check ACK list for messages that need to be re-sent because they haven't been ACK'd + checkPendingACKList(); } /************************************************************************* @@ -721,11 +784,19 @@ // TODO - check CRC before processing a message if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) { - processReceivedMessage( &message.msg ); + // if ACK, + if ( MSG_ID_ACK == message.msg.hdr.msgID ) + { + matchACKtoPendingACKList( message.msg.hdr.seqNo ); + } + else + { + processReceivedMessage( &message.msg ); + } } else // CRC failed { - // TODO - probably wouldn't want to fault on this. ignore? + checkTooManyBadMsgCRCs( message.msg.hdr.msgID ); } } } @@ -734,18 +805,185 @@ } /************************************************************************* + * @brief checkForCommTimeouts + * The checkForCommTimeouts function checks for sub-system communication \n + * timeout errors. + * @details + * Inputs : timeOfLastDGCheckIn, timeOfLastUICheckIn + * Outputs : possibly a comm t/o alarm + * @param none + * @return none + *************************************************************************/ +static void checkForCommTimeouts( void ) +{ + if ( TRUE == uiDidCommunicate ) + { + if ( TRUE == didTimeout( timeOfLastUICheckIn, UI_COMM_TIMEOUT_IN_MS ) ) + { + activateAlarmNoData( ALARM_ID_UI_COMM_TIMEOUT ); + } + } + // TODO - check DG comm timeout +} + +/************************************************************************* + * @brief checkTooManyBadMsgCRCs + * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs \n + * within a set period of time. Assumed function is being called when a new \n + * bad CRC is detected so a new bad CRC will be added to the list. + * @details + * Inputs : badCRCTimeStamps[], badCRCListIdx, badCRCListCount + * Outputs : possibly a "too many bad CRCs" alarm + * @param msgID : the message ID from the recevied msg that failed CRC check. + * @return none + *************************************************************************/ +static void checkTooManyBadMsgCRCs( U16 msgID ) +{ + U32 listTimeInMS = calcTimeSince( badCRCTimeStamps[ badCRCListIdx ] ); + + // replace oldest bad CRC in list with this new one + badCRCTimeStamps[ badCRCListIdx ] = getMSTimerCount(); + // move list index to next position (may wrap) + badCRCListIdx = INC_WRAP( badCRCListIdx, 0, MAX_COMM_CRC_FAILURES ); + // update list count + badCRCListCount = INC_CAP( badCRCListCount, MAX_COMM_CRC_FAILURES ); + // check if too many bad CRCs in window of time + if ( listTimeInMS >= MAX_COMM_CRC_FAILURE_WINDOW_MS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_COMM_TOO_MANY_BAD_CRCS, (U32)msgID ); + } +} + +#ifdef ACK_IMPLEMENTED +/************************************************************************* + * @brief addMsgToPendingACKList + * The addMsgToPendingACKList function adds a given message to the pending \n + * ACK list. Messages in this list will require receipt of an ACK message \n + * for this particular message within a limited time. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param msg : pointer to msg within the message data + * @param msgData : pointer to message data to add to pending ACK list + * @param len : # of bytes of message data + * @return TRUE if message added successfully, FALSE if not + *************************************************************************/ +BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) +{ + BOOL result = FALSE; + U32 i; + + // find first open slot in pending ACK list and add given msg data to it + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + _disable_IRQ(); // slot selection needs interrupt protection + if ( FALSE == pendingAckList[ i ].used ) + { + pendingAckList[ i ].used = TRUE; + _enable_IRQ(); + pendingAckList[ i ].seqNo = msg->hdr.seqNo &= ~MSG_ACK_BIT; + pendingAckList[ i ].channel = channel; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; + pendingAckList[ i ].msgSize = len; + memcpy( pendingAckList[ i ].msg, msgData, len ); + result = TRUE; + break; + } + else + { + _enable_IRQ(); + } + } + + return result; +} + +/************************************************************************* + * @brief matchACKtoPendingACKList + * The matchACKtoPendingACKList function searches the pending ACK list to \n + * see if the sequence # from a received ACK msg matches any. If found, \n + * the list entry is removed. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param seqNo : sequence # to match to an entry in the list + * @return TRUE if a match was found, FALSE if not + *************************************************************************/ +static BOOL matchACKtoPendingACKList( U16 seqNo ) +{ + BOOL result = FALSE; + U32 i; + + // find match + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) + { + pendingAckList[ i ].used = FALSE; + result = TRUE; + break; + } + } + + return result; +} + +/************************************************************************* + * @brief checkPendingACKList + * The checkPendingACKList function searches the pending ACK list to \n + * see if any have expired. Any such messages will be queued for retransmission \n + * and if max retries reached a fault is triggered. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param none + * @return none + *************************************************************************/ +static void checkPendingACKList( void ) +{ + U32 i; + + // find expired messages pending ACK + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) + { + if ( pendingAckList[ i ].retries > 0 ) + { // re-queue message for transmit + pendingAckList[ i ].retries--; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); + } + else + { + // TODO - fault + } + } + } +} +#endif + +/************************************************************************* * @brief processReceivedMessage * The processReceivedMessage function processes a given message. * @details * Inputs : none * Outputs : message processed - * @param msg : + * @param message : pointer to message to process * @return none *************************************************************************/ static void processReceivedMessage( MESSAGE_T *message ) { U16 msgID = message->hdr.msgID; + // if received message requires ACK, queue one up + if ( ( message->hdr.seqNo & MSG_ACK_BIT ) != 0 ) + { + sendACKMsg( message ); + } + + // handle any messages from other sub-systems switch ( msgID ) { case MSG_ID_OFF_BUTTON_PRESS: Index: firmware/App/Services/SystemComm.h =================================================================== diff -u -r52863cba9685f31136ab3f4b4764a17ccf34fc05 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision 52863cba9685f31136ab3f4b4764a17ccf34fc05) +++ firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -19,6 +19,7 @@ #include "Common.h" #include "CommBuffers.h" +#include "MsgQueues.h" // ********** public definitions ********** @@ -27,6 +28,12 @@ #define CAN_MESSAGE_PAYLOAD_SIZE 8 #define PC_MESSAGE_PACKET_SIZE 8 +#define MSG_ID_ACK 0xFFFF +#define MSG_ACK_BIT 0x8000 +#define MAX_MSG_SEQ_NO 0x7FFF +#define MIN_MSG_SEQ_NO 0x0001 +#define MAX_ACK_MSG_SIZE ( sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ) // must hold full (wrapped) message + sync + any CAN padding + typedef COMM_BUFFER_T CAN_MESSAGE_BOX_T; // the first 12 comm buffers align with the 12 active CAN message boxes // ********** public function prototypes ********** @@ -42,5 +49,8 @@ BOOL isDGCommunicating( void ); BOOL isUICommunicating( void ); BOOL uiCommunicated( void ); +#ifdef ACK_IMPLEMENTED +BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ); +#endif #endif Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -31,6 +31,9 @@ // ********** private definitions ********** +#define ACK_REQUIRED TRUE +#define ACK_NOT_REQUIRED FALSE + #pragma pack(push,1) typedef struct @@ -62,36 +65,55 @@ // ********** private data ********** static BOOL testerLoggedIn = FALSE; +static volatile U16 nextSeqNo = 1; // ********** private function prototypes ********** -static U32 serializeMessage( MESSAGE_T msg, U08 *data ); +static U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ); static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); /************************************************************************* * @brief serializeMessage * The serializeMessage function serializes a given message into a given \n - * array of bytes. A sync byte is inserted at the beginning of the message \n - * and an 8-bit CRC is appended to the end of the message. The given array \n - * must be large enough to hold the message + 1 sync byte and 1 CRC byte and \n - * up to 7 CAN padding bytes. + * 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. + * Outputs : given data array populated with serialized message data and queued for transmit. * @param msg : message to serialize - * @param data : byte array to populate with message data + * @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, U08 *data ) +static U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) { + BOOL result; U32 msgSize = 0; U32 sizeMod, sizePad; U32 i; - U08 crc = crc8( (U08*)(&msg), sizeof( MESSAGE_HEADER_T ) + msg.hdr.payloadLen ); + 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 +#ifdef ACK_IMPLEMENTED + _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 |= MSG_ACK_BIT; + } +#endif + + // 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 ); @@ -111,9 +133,52 @@ data[ msgSize++ ] = 0; } - return msgSize; +#ifdef ACK_IMPLEMENTED + // if ACK required, add to pending ACK list + if ( TRUE == ackReq ) + { + if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) + { + // TODO - ??? + } + } +#endif + + // 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; + msg.hdr.seqNo &= ~MSG_ACK_BIT; + // ACK messages always have this ID + msg.hdr.msgID = MSG_ID_ACK; + + // serialize the message (w/ sync, CRC, and appropriate CAN padding) + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_BROADCAST, ACK_NOT_REQUIRED ); + + return result; +} + // *********************************************************************** // ********************* MSG_ID_OFF_BUTTON_PRESS ************************* // *********************************************************************** @@ -133,21 +198,16 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_OFF_BUTTON_PRESS; - msg.hdr.payloadLen = 1; + msg.hdr.payloadLen = sizeof( U08 ); msg.payload[ 0 ] = cmd; - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_2_UI, ACK_NOT_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_2_UI, data, msgSize ); - return result; } @@ -183,8 +243,6 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; ALARM_COMP_STATUS_PAYLOAD_T payload; @@ -209,12 +267,9 @@ memcpy( payloadPtr, &payload, sizeof( ALARM_COMP_STATUS_PAYLOAD_T ) ); - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_ALARM, ACK_NOT_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); - return result; } @@ -234,8 +289,6 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record @@ -249,12 +302,9 @@ payloadPtr += sizeof( ALARM_DATA_T ); memcpy( payloadPtr, &almData2, sizeof( ALARM_DATA_T ) ); - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_ALARM, ACK_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); - return result; } @@ -272,8 +322,6 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; // create a message record @@ -283,12 +331,9 @@ memcpy( payloadPtr, &alarm, sizeof( U16 ) ); - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_ALARM, ACK_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_ALARM, data, msgSize ); - return result; } @@ -312,8 +357,6 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; PERISTALTIC_PUMP_STATUS_PAYLOAD_T payload; @@ -332,12 +375,9 @@ memcpy( payloadPtr, &payload, sizeof( PERISTALTIC_PUMP_STATUS_PAYLOAD_T ) ); - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_BROADCAST, data, msgSize ); - return result; } @@ -361,8 +401,6 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ sizeof( MESSAGE_WRAPPER_T ) + 1 + CAN_MESSAGE_PAYLOAD_SIZE ]; // must hold full (wrapped) message + sync + any CAN padding U08 *payloadPtr = msg.payload; PERISTALTIC_PUMP_STATUS_PAYLOAD_T payload; @@ -381,12 +419,9 @@ memcpy( payloadPtr, &payload, sizeof( PERISTALTIC_PUMP_STATUS_PAYLOAD_T ) ); - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_HD_BROADCAST, data, msgSize ); - return result; } @@ -437,21 +472,9 @@ BOOL sendDebugData( U08 *dbgData, U32 len ) { BOOL result; - MESSAGE_T msg; - U32 msgSize; - U08 data[sizeof(MESSAGE_WRAPPER_T) + 1 + CAN_MESSAGE_PAYLOAD_SIZE]; // must hold full (wrapped) message + sync + any CAN padding - // create a message record - blankMessage( &msg ); - msg.hdr.msgID = 2; - msg.hdr.payloadLen = len; - memcpy( msg.payload, dbgData, len ); - - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_UART_PC, data, msgSize ); + result = addToCommBuffer( COMM_BUFFER_OUT_UART_PC, dbgData, len ); return result; } @@ -487,21 +510,16 @@ { BOOL result; MESSAGE_T msg; - U32 msgSize; - U08 data[ PC_MESSAGE_PACKET_SIZE ]; // create a message record blankMessage( &msg ); msg.hdr.msgID = msgID; - msg.hdr.payloadLen = 1; + msg.hdr.payloadLen = sizeof( U08 ); msg.payload[ 0 ] = (U08)ack; - // serialize the message (w/ sync, CRC, and appropriate CAN padding) - msgSize = serializeMessage( msg, data ); + // 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 ); - // add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_CAN_PC, data, msgSize ); - return result; } Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -65,6 +65,9 @@ // ********** public function prototypes ********** +// ACK MSG +BOOL sendACKMsg( MESSAGE_T *message ); + // MSG_ID_OFF_BUTTON_PRESS BOOL sendOffButtonMsgToUI( U08 cmd ); void handleOffButtonConfirmMsgFromUI( MESSAGE_T *message ); @@ -162,5 +165,5 @@ // MSG_ID_DIAL_PUMP_MEAS_ROTOR_SPEED_OVERRIDE void handleTestDialPumpRotorMeasuredSpeedOverrideRequest( MESSAGE_T *message ); - #endif + Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -64,7 +64,7 @@ execBloodFlowController(); // control dialysate inlet pump - execDialInFlowController(); + //execDialInFlowController(); // manage alarm state execAlarmMgmt(); Index: firmware/App/Tasks/TaskPriority.c =================================================================== diff -u -rf7e3018ec6ab762fe08efb42b21fb2ca970174b0 -r9864b14f76782f1e68bf266dcd843451748715a0 --- firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision f7e3018ec6ab762fe08efb42b21fb2ca970174b0) +++ firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 9864b14f76782f1e68bf266dcd843451748715a0) @@ -53,11 +53,10 @@ execBloodFlowMonitor(); // monitor dialysate inlet pump and flow - execDialInFlowMonitor(); + //execDialInFlowMonitor(); // 2nd pass for FPGA execFPGAOut(); - } // check in with watchdog manager