Index: firmware/App/Controllers/AirTrap.c =================================================================== diff -u -r7c10a7dc0c191b2680ae51af8d2dff2bd6b70878 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision 7c10a7dc0c191b2680ae51af8d2dff2bd6b70878) +++ firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/AlarmLamp.c =================================================================== diff -u -rb0cfdf88d0aeba4bea316388158d77fb0d0f4537 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/AlarmLamp.c (.../AlarmLamp.c) (revision b0cfdf88d0aeba4bea316388158d77fb0d0f4537) +++ firmware/App/Controllers/AlarmLamp.c (.../AlarmLamp.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/BloodFlow.c =================================================================== diff -u -rf1c099b79e0825afe54379577454518f7a134a73 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision f1c099b79e0825afe54379577454518f7a134a73) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -93,7 +93,13 @@ #define BP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define BP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor. +#define BLOODPUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref may be different). +#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. + +/// Macro converts 12 bit ADC value to signed 16-bit value. +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) + +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor (3500 RPM/1998 counts). #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 BP motor RPM = 1% PWM duty cycle. #define BP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for blood pump motor. @@ -108,20 +114,16 @@ /// Conversion from PWM duty cycle % to commanded pump motor speed. #define BP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - BP_PWM_ZERO_OFFSET) * 4000.0 ) -#define BLOODPUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref may be different). -#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. -/// Macro converts 12 bit ADC value to signed 16-bit value. -#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) - /// Measured blood flow is filtered w/ moving average. #define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 1 ) #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. -#define BP_FLOW_ALPHA_Y_INTERCEPT 1.218 ///< Y intercept used for alpha flow coefficient calculation. -#define BP_FLOW_WEAR_A_TERM 0.000000007474 ///< A term used for wear portion of alpha flow coefficient. -#define BP_FLOW_WEAR_B_TERM 0.0006053 ///< B term used for wear portion of alpha flow coefficient. +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.2163 ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.000000005665 ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.0006125 ///< B term used for wear portion of alpha flow coefficient. #define BP_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define BP_FLOW_CORRECTION_FACTOR 0.9 // TODO - why do we need this /// Enumeration of blood pump controller states. typedef enum BloodPump_States @@ -225,7 +227,7 @@ { U32 i; - stopBloodPump(); + signalBloodPumpHardStop(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); // Zero rolling pump speed average buffer @@ -271,58 +273,64 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isBloodPumpOn ) || ( 0 == flowRate ) || ( dir == bloodPumpDirectionSet ) ) - { + { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) + { #ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) + // Verify flow rate + if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) #endif - { - resetBloodPumpRPMMovingAverage(); - targetBloodFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); - bloodPumpDirection = dir; - bloodPumpControlMode = mode; - // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will 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%) - - switch ( bloodPumpState ) { - case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - break; + resetBloodPumpRPMMovingAverage(); + targetBloodFlowRate = dirFlowRate; + bloodPumpDirection = dir; + bloodPumpControlMode = mode; + // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will 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%) - case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; + switch ( bloodPumpState ) + { + case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + break; - case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction - if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - else - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; + case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; - default: - // Ok - not all states need to be handled here - break; + case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + else + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; + + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; } - result = TRUE; - } #ifndef NO_PUMP_FLOW_LIMITS - else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) - } -#endif + else // Requested flow rate too high + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) + } +#endif + } } return result; @@ -339,17 +347,18 @@ *************************************************************************/ static F32 calcBloodFlow( void ) { +#ifndef PBA_ESTIMATION F32 artPres = getLongFilteredArterialPressure(); +#else + // TODO - temporary test code - remove later + F32 artPres = -200.0; +#endif F32 rotSpd = filteredBloodPumpSpeed / BP_GEAR_RATIO; -#ifndef WORN_OUT_CARTRIDGE U32 r = getBloodPumpRotorCount(); U32 rotCnt = CAP( r, BP_MAX_ROTOR_COUNT_FOR_WEAR ); -#else - U32 rotCnt = BP_MAX_ROTOR_COUNT_FOR_WEAR; -#endif F32 wear = BP_FLOW_WEAR_A_TERM * (F32)rotCnt + BP_FLOW_WEAR_B_TERM; F32 alpha = wear * artPres + BP_FLOW_ALPHA_Y_INTERCEPT; - F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd * BP_FLOW_CORRECTION_FACTOR; return flow; } @@ -478,7 +487,11 @@ *************************************************************************/ void resetBloodPumpRotorCount( void ) { +#ifndef WORN_OUT_CARTRIDGE bloodPumpRotorCounter.data = 0; +#else + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; +#endif } /*********************************************************************//** @@ -639,7 +652,7 @@ // Have we essentially reached zero speed? if ( bloodPumpPWMDutyCyclePctSet < (MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE + BP_PWM_ZERO_OFFSET) ) { - stopBloodPump(); + signalBloodPumpHardStop(); result = BLOOD_PUMP_OFF_STATE; } // Have we reached end of ramp down? @@ -1042,7 +1055,9 @@ if ( lastBloodPumpDirectionCount != dirErrorCnt ) { lastBloodPumpDirectionCount = dirErrorCnt; +#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) +#endif } #endif bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); @@ -1172,23 +1187,6 @@ { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); } - - // Flow vs. speed check only performed while in treatment mode and while we are in control to target state - if ( ( MODE_TREA == getCurrentOperationMode() ) && ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) ) - { - F32 speed = getMeasuredBloodPumpSpeed(); - F32 impliedSpeed = ( (F32)targetBloodFlowRate / (F32)ML_PER_LITER ) * BP_REV_PER_LITER * BP_GEAR_RATIO; - F32 delta = fabs( speed - impliedSpeed ); - - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, delta > BP_MAX_FLOW_VS_SPEED_DIFF_RPM ) ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, flow, speed ); - } - } - else - { - resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK ); - } #endif } Index: firmware/App/Controllers/BloodLeak.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -14,6 +14,7 @@ * @date (original) 18-Mar-2021 * ***************************************************************************/ +#include // For sprintf #include "AlarmMgmt.h" #include "BloodLeak.h" @@ -30,60 +31,112 @@ // ********** private definitions ********** -#define BLOOD_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the blood leak data is published on the CAN bus. -#define BLOOD_LEAK_TIMEOUT_MS 500 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) +#define BLOOD_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the blood leak data is published on the CAN bus. +#define BLOOD_LEAK_TIMEOUT_MS 500 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) +#define BLOOD_LEAK_PERSISTENCE ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence for blood leak detected alarm. +#define BLOOD_LEAK_RESET_TX_FIFO 2 ///< Blood leak reset transmit FIFO command. +#define BLOOD_LEAK_START_COMM_CTRL_U_ASCII 21 ///< Blood leak start communication command, ^U (Ctrl-U) in ascii. +#define BLOOD_LEAK_UART_COMM_ACTIVE_LOW 0 ///< Blood leak UART communication active low command. +#define BLOOD_LEAK_UART_COMM_ACTIVE_HIGH 1 ///< Blood leak UART communication active high command. +#define BLOOD_LEAK_STARTUP_SEQ_LENGTH 5 ///< Blood leak start up sequence array length. +#define BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH 4 ///< Blood leak set point maximum character length. +#define BLOOD_LEAK_SET_POINT_START_CHAR_ASCII 83 ///< Blood leak set point sequence start character in ASCII (letter S). +#define BLOOD_LEAK_SET_POINT_START_CHAR_INDEX 0 ///< Blood leak set point sequence start character index number. +#define BLOOD_LEAK_CARRIAGE_RETURN_ASCII 13 ///< Blood leak set point sequence carriage return character in ASCII. +#define BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH 7 ///< Blood leak set point sequence maximum length. + +#define BLOOD_LEAK_WAIT_2_READ_SET_POINT ( 0.5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Blood leak wait to read set point in counts. +#define BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS 3 ///< Blood leak maximum number of trials to write the set point. + /// Defined states for the blood leak detector state machine. typedef enum BloodLeakStates { - BLOOD_LEAK_INIT_STATE = 0, ///< Initial state - BLOOD_LEAK_ZERO_STATE, ///< Zero state - BLOOD_LEAK_SELF_TEST_STATE, ///< Self-test state - BLOOD_LEAK_NORMAL_STATE, ///< Normal state - NUM_OF_BLOOD_LEAK_STATES ///< Number of blood leak detector states + BLOOD_LEAK_START_UP_STATE = 0, ///< Start up state. + BLOOD_LEAK_CHECK_SET_POINT_STATE, ///< Check set point state. + BLOOD_LEAK_SET_SET_POINT_STATE, ///< Set set point state. + BLOOD_LEAK_INIT_STATE, ///< Init state. + BLOOD_LEAK_ZERO_STATE, ///< Zero state. + BLOOD_LEAK_SELF_TEST_STATE, ///< Self-test state. + BLOOD_LEAK_NORMAL_STATE, ///< Normal state. + NUM_OF_BLOOD_LEAK_STATES ///< Number of blood leak detector states. } BLOOD_LEAK_STATES_T; // ********** private data ********** -static BLOOD_LEAK_STATES_T bloodLeakState; ///< Current state of blood leak state machine. -static OVERRIDE_U32_T bloodLeakStatus; ///< Detected blood leak status for blood leak detector. -static SELF_TEST_STATUS_T bloodLeakSelfTestStatus; ///< Current status of blood leak self-test. +static BLOOD_LEAK_STATES_T bloodLeakState; ///< Current state of blood leak state machine. +static OVERRIDE_U32_T bloodLeakStatus; ///< Detected blood leak status for blood leak detector. +static SELF_TEST_STATUS_T bloodLeakSelfTestStatus; ///< Current status of blood leak self-test. -static BOOL bloodLeakZeroRequested = FALSE; ///< Blood leak zero requested flag -static U32 bloodLeakZeroStartTime = 0; ///< Blood leak zeroing start time. -static U32 bloodLeakSelfTestStartTime = 0; ///< Blood leak self-test start time. +static BOOL bloodLeakZeroRequested = FALSE; ///< Blood leak zero requested flag +static U32 bloodLeakZeroStartTime = 0; ///< Blood leak zeroing start time. +static U32 bloodLeakSelfTestStartTime = 0; ///< Blood leak self-test start time. -/// Interval (in ms) at which to publish blood leak data to CAN bus. -static OVERRIDE_U32_T bloodLeakDataPublishInterval = { BLOOD_LEAK_PUB_INTERVAL, BLOOD_LEAK_PUB_INTERVAL, 0, 0 }; -static U32 bloodLeakDataPublicationTimerCounter = 0; ///< Timer counter used to schedule blood leak data publication to CAN bus. +static U32 bloodLeakPersistenceCtr = 0; ///< Blood leak alarm persistence timer counter. +static OVERRIDE_U32_T bloodLeakDataPublishInterval = { BLOOD_LEAK_PUB_INTERVAL, + BLOOD_LEAK_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish blood leak data to CAN bus. +static U32 bloodLeakDataPublicationTimerCounter = 0; ///< Timer counter used to schedule blood leak data publication to CAN bus. +static U32 bloodLeakUARTCmdIndex; ///< Blood leak UART command index. +static U32 bloodLeakSetPointSeqLength = 0; ///< Blood leak set point sequence actual length. +static U08 bloodLeakSetPointSequence[ BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ]; ///< Blood leak set point sequence array. +static U32 bloodLeakWait2ReadSetPointCounter = 0; ///< Blood leak wait to read delay counter. +static U32 bloodLeakCurrentSetPointWriteTry = 0; + + +/// Blood leak start up sequence array. +static const U08 BLOOD_LEAK_START_UP_SEQUENCE[ BLOOD_LEAK_STARTUP_SEQ_LENGTH ] = { BLOOD_LEAK_RESET_TX_FIFO, + BLOOD_LEAK_UART_COMM_ACTIVE_LOW, + BLOOD_LEAK_START_COMM_CTRL_U_ASCII, + BLOOD_LEAK_UART_COMM_ACTIVE_HIGH, + BLOOD_LEAK_UART_COMM_ACTIVE_LOW }; +static const U32 REMOVE_LATER_SET_POINT = 38; // TODO remove this later +static U32 test = 38; + + // ********** private function prototypes ********** +static BLOOD_LEAK_STATES_T handleBloodLeakStartupState( void ); +static BLOOD_LEAK_STATES_T handleBloodLeakCheckSetPointState( void ); +static BLOOD_LEAK_STATES_T handleBloodLeakSetSetPointState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakInitState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakZeroState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakSelfTestState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakNormalState( void ); +static void prepareSetPointSeq( void ); static void publishBloodLeakData( void ); /*********************************************************************//** * @brief * The initBloodLeak function initializes the Blood Leak module. * @details Inputs: none - * @details Outputs: Blood Leak module initialized. + * @details Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, + * bloodLeakZeroRequested, bloodLeakZeroRequested, bloodLeakSelfTestStartTime, + * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence, + * bloodLeakWait2ReadSetPointCounter, bloodLeakDataPublicationTimerCounter, + * bloodLeakCurrentSetPointWriteTry * @return none *************************************************************************/ void initBloodLeak( void ) { - bloodLeakState = BLOOD_LEAK_INIT_STATE; - bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; - bloodLeakStatus.ovInitData = BLOOD_LEAK_NOT_DETECTED; - bloodLeakStatus.ovData = BLOOD_LEAK_NOT_DETECTED; - bloodLeakStatus.override = OVERRIDE_RESET; - bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; - bloodLeakZeroRequested = FALSE; - bloodLeakZeroStartTime = 0; - bloodLeakSelfTestStartTime = 0; + bloodLeakDataPublicationTimerCounter = 0; + bloodLeakState = BLOOD_LEAK_START_UP_STATE; + bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; + bloodLeakStatus.ovInitData = BLOOD_LEAK_NOT_DETECTED; + bloodLeakStatus.ovData = BLOOD_LEAK_NOT_DETECTED; + bloodLeakStatus.override = OVERRIDE_RESET; + bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; + bloodLeakZeroRequested = FALSE; + bloodLeakZeroStartTime = 0; + bloodLeakSelfTestStartTime = 0; + bloodLeakUARTCmdIndex = 0; + bloodLeakSetPointSeqLength = 0; + bloodLeakWait2ReadSetPointCounter = 0; + bloodLeakCurrentSetPointWriteTry = 0; + + // Set the blood leak set pint sequence to 0 to be initialized + memset( bloodLeakSetPointSequence, 0x0, BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ); } /*********************************************************************//** @@ -100,6 +153,18 @@ // Execute blood leak state machine switch( bloodLeakState ) { + case BLOOD_LEAK_START_UP_STATE: + bloodLeakState = handleBloodLeakStartupState(); + break; + + case BLOOD_LEAK_CHECK_SET_POINT_STATE: + bloodLeakState = handleBloodLeakCheckSetPointState(); + break; + + case BLOOD_LEAK_SET_SET_POINT_STATE: + bloodLeakState = handleBloodLeakSetSetPointState(); + break; + case BLOOD_LEAK_INIT_STATE: bloodLeakState = handleBloodLeakInitState(); break; @@ -142,10 +207,129 @@ /*********************************************************************//** * @brief + * The handleBloodLeakStartupState function handles the startup state of the + * of blood leak state machine. + * @details Inputs: bloodLeakUARTCmdIndex + * @details Outputs: bloodLeakUARTCmdIndex + * @return next state + *************************************************************************/ +static BLOOD_LEAK_STATES_T handleBloodLeakStartupState( void ) +{ + BLOOD_LEAK_STATES_T state = BLOOD_LEAK_START_UP_STATE; + + U32 command = BLOOD_LEAK_START_UP_SEQUENCE[ bloodLeakUARTCmdIndex ]; + + if ( BLOOD_LEAK_START_COMM_CTRL_U_ASCII == command ) + { + setFPGABloodLeakUARTTransmit( (U08)command ); + } + else + { + setFPGABloodLeakUARTControl( (U08)command ); + } + + if ( bloodLeakUARTCmdIndex > BLOOD_LEAK_STARTUP_SEQ_LENGTH - 1 ) + { + bloodLeakUARTCmdIndex = 0; + state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + } + else + { + bloodLeakUARTCmdIndex++; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBloodLeakCheckSetPointState function handles the check set point + * state to ensure the set point is set correctly. + * @details Inputs: none + * @details Outputs: bloodLeakUARTCmdIndex + * @return next state + *************************************************************************/ +static BLOOD_LEAK_STATES_T handleBloodLeakCheckSetPointState( void ) +{ + BLOOD_LEAK_STATES_T state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + + U32 bloodLeakSetPoint = (U32)getFPGABloodLeakDetectSetPoint(); + + if ( bloodLeakSetPoint != REMOVE_LATER_SET_POINT ) + { + if ( bloodLeakCurrentSetPointWriteTry < BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS ) + { + prepareSetPointSeq(); + + bloodLeakUARTCmdIndex = 0; + state = BLOOD_LEAK_SET_SET_POINT_STATE; + } + else + { + // TODO fault alarm that we cannot write to blood leak? + } + + } + else + { + state = BLOOD_LEAK_INIT_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleBloodLeakSetSetPointState function handles the set set point state. + * @details Inputs: bloodLeakUARTCmdIndex + * @details Outputs: bloodLeakUARTCmdIndex, bloodLeakSetPointSeqLength + * @return next state + *************************************************************************/ +static BLOOD_LEAK_STATES_T handleBloodLeakSetSetPointState( void ) +{ + BLOOD_LEAK_STATES_T state = BLOOD_LEAK_SET_SET_POINT_STATE; + + // Check if the current buffer index is less than the buffer length + if( bloodLeakUARTCmdIndex < bloodLeakSetPointSeqLength ) + { + U32 command = bloodLeakSetPointSequence[ bloodLeakUARTCmdIndex ]; + + // The active high index is the length - 2 they are the last two elements + U32 activeHighIndex = bloodLeakSetPointSeqLength - 2; + + // Check if the current index towards the end of the buffer which are 1 and 0 + if( activeHighIndex > bloodLeakUARTCmdIndex ) + { + setFPGABloodLeakUARTTransmit( (U08)command ); + } + else + { + setFPGABloodLeakUARTControl( (U08)command ); + } + + bloodLeakUARTCmdIndex++; + } + else + { + if ( ++bloodLeakWait2ReadSetPointCounter > BLOOD_LEAK_WAIT_2_READ_SET_POINT ) + { + bloodLeakWait2ReadSetPointCounter = 0; + bloodLeakUARTCmdIndex = 0; + + // Done with writing the set point + state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleBloodLeakInitState function handles the Blood Leak module in init * state. * @details Inputs: none - * @details Outputs: Blood Leak module init. + * @details Outputs: none * @return next state *************************************************************************/ static BLOOD_LEAK_STATES_T handleBloodLeakInitState( void ) @@ -178,10 +362,14 @@ if ( TRUE == FPGABloodLeakZeroDetected() ) { - state = BLOOD_LEAK_SELF_TEST_STATE; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; clearFPGABloodLeakZero(); +#ifndef IGNORE_BLOOD_LEAK_SELF_TEST setFPGABloodLeakSelfTest(); + state = BLOOD_LEAK_SELF_TEST_STATE; +#else + state = BLOOD_LEAK_NORMAL_STATE; +#endif bloodLeakSelfTestStartTime = getMSTimerCount(); } else @@ -207,6 +395,7 @@ { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_SELF_TEST_STATE; +#ifndef IGNORE_BLOOD_LEAK_SELF_TEST if ( SELF_TEST_STATUS_IN_PROGRESS == bloodLeakSelfTestStatus ) { if ( FALSE == noFPGABloodLeakDetected() ) // Faked blood leak caused by independent MCU board @@ -217,8 +406,9 @@ else if ( TRUE == didTimeout( bloodLeakSelfTestStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; + activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SELF_TEST_FAILURE ); - } + } } else { @@ -228,6 +418,9 @@ state = BLOOD_LEAK_NORMAL_STATE; } } +#else + state = BLOOD_LEAK_NORMAL_STATE; +#endif return state; } @@ -254,21 +447,29 @@ } // Check status reading and act upon - if ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) + if ( ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) && ( MODE_TREA == getCurrentOperationMode() ) ) { - if ( getCurrentOperationMode() == MODE_TREA ) + if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { + bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; +#ifndef IGNORE_BLOOD_LEAK_ALARM activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); +#endif } + } + else // Blood leak not detected + { + if ( bloodLeakPersistenceCtr > 0 ) + { + bloodLeakPersistenceCtr--; + } else { - activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); +#ifndef IGNORE_BLOOD_LEAK_ALARM + clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); +#endif } } - else // Blood leak not detected - { - clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); - } if ( TRUE == bloodLeakZeroRequested ) { @@ -317,21 +518,91 @@ /*********************************************************************//** * @brief + * The prepareSetPointSeq function prepares the set point sequence to be + * written to the blood leak sensor. + * @details Inputs: none + * @details Outputs: bloodLeakSetPointSequence, bloodLeakSetPointSeqLength + * @return none + *************************************************************************/ +static void prepareSetPointSeq( void ) +{ + U08 i; + // Set the local variables. Create a local char buffer with the maximum possible length + // The set point can be maximum 3 digits and when it is converted to string, the null character + // is the extra character at the end of the buffer so it maximum length is 4 bytes. + U32 digitCount = 0; + U32 setPoint = test; // TODO make the origin of the number right + U32 bufferIndex = BLOOD_LEAK_SET_POINT_START_CHAR_INDEX; + char tempCharBuffer[ BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH ]; + memset( tempCharBuffer, 0x0, BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH ); + + while ( setPoint != 0 ) + { + // Calculate the number of digits of the set point + // Keep dividing the set point to 10 and count the digits until the set point + // is 0. This value is an unsigned integer. + setPoint = setPoint / 10; + digitCount++; + } + + // + setPoint = test; + + // Convert the set point number to the equivalent ASCII number with the unsigned integer data type + sprintf( tempCharBuffer, "%u", setPoint ); + + // Set the first item to the ASCII character of S. The format to set the set point is + // SXXXCR10. It starts with S followed by the characters up to 3 digits, carriage return and a 1 and a 0 to write to the buffer. + bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_SET_POINT_START_CHAR_ASCII; + // Increment the buffer index + bufferIndex++; + + // Loop through the number of digits and get each ASCII value + for ( i = 0; i < digitCount; i++ ) + { + // Write the characters + bloodLeakSetPointSequence[ bufferIndex ] = tempCharBuffer[ i ]; + bufferIndex++; + } + + // After the characters, insert the carriage return into the buffer + bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_CARRIAGE_RETURN_ASCII; + bufferIndex++; + // Set active high and active low into the buffer + bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_UART_COMM_ACTIVE_HIGH; + bufferIndex++; + + bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_UART_COMM_ACTIVE_LOW; + // Update the sequence length for writing to the sensor + bloodLeakSetPointSeqLength = bufferIndex + 1; +} + +/*********************************************************************//** + * @brief * The publishBloodLeakData function publishes blood leak data at the set interval. - * @details Inputs: bloodLeakStatus, bloodLeakState - * @details Outputs: if broadcast is due, send blood leak data + * @details Inputs: bloodLeakDataPublicationTimerCounter + * @details Outputs: bloodLeakDataPublicationTimerCounter * @return none *************************************************************************/ static void publishBloodLeakData( void ) { // Publish blood leak data on interval if ( ++bloodLeakDataPublicationTimerCounter >= getU32OverrideValue( &bloodLeakDataPublishInterval ) ) { - BLOOD_LEAK_DATA_T bloodLeakData; + BLOOD_LEAK_DATA_T data; - bloodLeakData.bloodLeakStatus = (U32)getBloodLeakStatus(); - bloodLeakData.bloodLeakState = (U32)bloodLeakState; - broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&bloodLeakData, sizeof( BLOOD_LEAK_DATA_T ) ); + data.bloodLeakStatus = (U32)getBloodLeakStatus(); + data.bloodLeakState = (U32)bloodLeakState; + data.bloodLeakZeroStatusCounter = (U32)getFPGABloodLeakZeroStatusCounter(); + data.bloodLeakCounter = (U32)getFPGABloodLeakCounter(); + data.bloodLeakZeroedStatus = (U32)getFPGABloodLeakZeroedStatus(); + data.bloodLeakDetectSetPoint = (U32)getFPGABloodLeakDetectSetPoint(); + data.bloodLeakDetectLevel = (U32)getFPGABloodLeakDetectLevel(); + data.bloodLeakStCount = (U32)getFPGABloodLeakStCount(); + data.bloodLeakLEDIntesity = (U32)getFPGABloodLeakLEDIntensity(); + data.bloodLeakRegisterCounter = (U32)getFPGABloodLeakRegisterCounter(); + + broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); bloodLeakDataPublicationTimerCounter = 0; } } @@ -360,7 +631,7 @@ U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; - bloodLeakDataPublishInterval.ovData = intvl; + bloodLeakDataPublishInterval.ovData = intvl; bloodLeakDataPublishInterval.override = OVERRIDE_KEY; } @@ -383,7 +654,7 @@ { result = TRUE; bloodLeakDataPublishInterval.override = OVERRIDE_RESET; - bloodLeakDataPublishInterval.ovData = bloodLeakDataPublishInterval.ovInitData; + bloodLeakDataPublishInterval.ovData = bloodLeakDataPublishInterval.ovInitData; } return result; @@ -408,7 +679,7 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - bloodLeakStatus.ovData = (U32)status; + bloodLeakStatus.ovData = (U32)status; bloodLeakStatus.override = OVERRIDE_KEY; } } @@ -433,7 +704,7 @@ { result = TRUE; bloodLeakStatus.override = OVERRIDE_RESET; - bloodLeakStatus.ovData = bloodLeakStatus.ovInitData; + bloodLeakStatus.ovData = bloodLeakStatus.ovInitData; } return result; Index: firmware/App/Controllers/BloodLeak.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/BloodLeak.h (.../BloodLeak.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/BloodLeak.h (.../BloodLeak.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -46,6 +46,14 @@ { U32 bloodLeakStatus; ///< Blood leak detector status U32 bloodLeakState; ///< Blood leak detector state + U32 bloodLeakZeroStatusCounter; ///< Blood leak zero status counter + U32 bloodLeakCounter; ///< Blood leak counter + U32 bloodLeakZeroedStatus; ///< Blood leak zeroed status + U32 bloodLeakDetectSetPoint; ///< Blood leak detect set point + U32 bloodLeakDetectLevel; ///< Blood leak detect level + U32 bloodLeakStCount; ///< Blood leak st count + U32 bloodLeakLEDIntesity; ///< Blood leak LED intensity + U32 bloodLeakRegisterCounter; ///< Blood leak register counter } BLOOD_LEAK_DATA_T; // ********** public function prototypes ********** @@ -55,7 +63,7 @@ void zeroBloodLeak( void ); BLOOD_LEAK_STATUS_T getBloodLeakStatus( void ); -SELF_TEST_STATUS_T getBloodLeakSelfTestStatus( void ); +SELF_TEST_STATUS_T getBloodLeakSelfTestStatus( void ); BOOL testSetBloodLeakDataPublishIntervalOverride( U32 value ); BOOL testResetBloodLeakDataPublishIntervalOverride( void ); Index: firmware/App/Controllers/Bubble.c =================================================================== diff -u -r946f42bfd6606dd3d771d9a4a7b50e5678469f62 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/Bubble.c (.../Bubble.c) (revision 946f42bfd6606dd3d771d9a4a7b50e5678469f62) +++ firmware/App/Controllers/Bubble.c (.../Bubble.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/Bubble.h =================================================================== diff -u -rdc5fda9a9930d6e1a33c4da0b509b3545acb947d -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/Bubble.h (.../Bubble.h) (revision dc5fda9a9930d6e1a33c4da0b509b3545acb947d) +++ firmware/App/Controllers/Bubble.h (.../Bubble.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/DGInterface.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -36,11 +36,7 @@ #define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. #define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. - -#define RESERVOIR_SETTLE_TIME_MS 5000 ///< Time (in ms) allotted for reservoir to settle (after fill, before drain). -#define MAX_RESERVOIR_VOLUME_ML 1950.0 ///< Maximum reservoir volume. Switch reservoirs if active reservoir exceeds this volume. - #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. #define DIALYSATE_TEMP_PERSISTENCE_PERIOD ( 3 * MS_PER_SECOND ) ///< Persistence period for dialysate temperature alarm. @@ -50,20 +46,6 @@ #define DIALYSATE_TEMP_HIGH_LIMIT_C 42.0 ///< Dialysate high temperature limit in degree C. #define DIALYSATE_TEMP_LOW_LIMIT_C 33.0 ///< Dialysate low temperature limit in degree C. -/// States of the treatment reservoir management state machine. -typedef enum TreatmentReservoirMgmt_States -{ - TREATMENT_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. - TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. - TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE, ///< Wait for drain to complete. - TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE, ///< Wait to fill inactive reservoir (if appropriate) - then start filling inactive reservoir. - TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE, ///< Wait for fill to complete. - TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE, ///< Wait a bit for filled reservoir to settle before getting baseline weight (volume). - TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE, ///< Wait for active reservoir to be consumed and switch cmd given - then back to flush DG lines state. - TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Wait for inactive reservoir to settle before getting final weight (volume) before starting to drain. - NUM_OF_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of treatment reservoir mgmt. states. -} TREATMENT_RESERVOIR_MGMT_STATE_T; - // ********** private data ********** // DG status @@ -74,14 +56,11 @@ static BOOL dgTrimmerHeaterOn = FALSE; ///< Flag indicates whether we have commanded the DG to start or stop the trimmer heater. // State machine states -/// Current state of treatment mode reservoir management. -static TREATMENT_RESERVOIR_MGMT_STATE_T currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; -static U32 resMgmtTimer = 0; ///< Used for keeping state time. +static U32 timeStartMS = 0; // TODO is this needed? // DG sensor data static F32 dgDialysateTemp = 0.0; ///< Dialysate temperature reported by the DG. static F32 dgRedundantDialysateTemp = 0.0; ///< Redundant dialysate temperature reported by the DG. -static F32 dgPrimaryTempSet = 0.0; ///< Primary heater target temperature commanded. static F32 dgPrimaryTemp = 0.0; ///< Latest RO water temperature reported by the DG. static F32 dgTrimmerTempSet = 0.0; ///< Trimmer heater target temperature commanded. static F32 dgTrimmerTemp = 0.0; ///< Latest dialysate temperature reported by the DG. @@ -108,17 +87,18 @@ static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. static U32 dgReservoirDrainVolumeTarget = 0; ///< Latest drain-to volume reported by the DG. static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. -static U32 resUseTimer = 0; ///< Used to track time pumping from active reservoir (for volume used calculation). -static F32 resUseVolumeMl = 0.0; ///< Accumulated volume used from active reservoir. + + static DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. +static DG_MIXING_RATIOS_T dgMixingRatios; ///< DG mixing ratios. // DG command response static DG_CMD_RESPONSE_T dgCmdResp[ NUM_OF_DG_COMMANDS ]; ///< Keep the latest DG command response for each command. // ********** private function prototypes ********** -static void checkDGRestart( void ); - +static void checkDGRestart( void ); + /*********************************************************************//** * @brief * The initDGInterface function initializes the DGInterface module. @@ -132,7 +112,6 @@ dgStarted = FALSE; dgTrimmerHeaterOn = FALSE; - dgPrimaryTempSet = 0.0; dgTrimmerTempSet = 0.0; dgActiveReservoirSet = DG_RESERVOIR_2; dgReservoirFillVolumeTargetSet = 0; @@ -188,23 +167,6 @@ checkDGRestart(); } - -/*********************************************************************//** - * @brief - * The initTreatmentReservoirMgmt function initializes the treatment reservoir - * management state machine. - * @details Inputs: none - * @details Outputs: treatment reservoir management state machine initialized. - * @return none - *************************************************************************/ -void initTreatmentReservoirMgmt( void ) -{ - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; - resMgmtTimer = 0; - resUseTimer = getMSTimerCount(); - resUseVolumeMl = 0.0; -} - /*********************************************************************//** * @brief * The dialysisResumed function initializes the reservoir re-use timer @@ -215,156 +177,11 @@ *************************************************************************/ void dialysisResumed( void ) { - resUseTimer = getMSTimerCount(); + timeStartMS = getMSTimerCount(); } -/*********************************************************************//** - * @brief - * The execTreatmentReservoirMgmt function executes the state machine for the - * reservoir management during treatment mode. - * @details Inputs: none - * @details Outputs: DG reservoirs (drains & fills) managed. - * @return none - *************************************************************************/ -void execTreatmentReservoirMgmt( void ) -{ - DG_OP_MODE_T dgOpMode = getDGOpMode(); - U32 dgSubMode = getDGSubMode(); - U32 msSinceLastVolumeCalc = calcTimeSince( resUseTimer ); - F32 flowRateMlPerMs = (F32)getTargetDialInFlowRate() / (F32)( MS_PER_SECOND * SEC_PER_MIN ); - - // Calculate volume used from active reservoir - do not accumulate if saline bolus in progress - if ( SALINE_BOLUS_STATE_IN_PROGRESS != getSalineBolusState() ) - { - resUseVolumeMl += ( flowRateMlPerMs * msSinceLastVolumeCalc ); - } - resUseTimer = getMSTimerCount(); - - // Alarm if active reservoir is full and inactive reservoir is not yet ready - if ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) - { - if ( currentTrtResMgmtState < TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_RESERVOIR_FULL_AND_DG_NOT_READY_TO_SWITCH, getReservoirWeight( getDGActiveReservoir() ), (F32)currentTrtResMgmtState ) - } - else - { - clearAlarmCondition( ALARM_ID_HD_RESERVOIR_FULL_AND_DG_NOT_READY_TO_SWITCH ); - } - } - - // Treatment reservoir mgmt. state machine - switch ( currentTrtResMgmtState ) - { - case TREATMENT_RESERVOIR_MGMT_START_STATE: - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; - break; - case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: - if ( DG_MODE_GENE == dgOpMode ) - { - if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) - { - cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE, FALSE, TRUE ); - } - } - else if ( DG_MODE_DRAI == dgOpMode ) - { - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; - } - else - { - // TODO - ??? - } - break; - case TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE: - if ( DG_MODE_GENE == dgOpMode ) - { - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; - } - break; - - case TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE: - // Delay fill start if we have paused treatment? - if ( getTreatmentState() == TREATMENT_DIALYSIS_STATE ) - { - if ( DG_MODE_GENE == dgOpMode ) - { - if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) - { - U32 fillToVolume = FILL_RESERVOIR_TO_VOLUME_ML; - - if ( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) <= SLOW_DIALYSATE_FLOW_ML_MIN ) - { - fillToVolume = FILL_RESERVOIR_TO_VOLUME_LOW_FLOW_ML; - } - cmdStartDGFill( fillToVolume ); - } - } - else - { - // TODO - ??? - } - } - if ( DG_MODE_FILL == dgOpMode ) - { - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; - } - break; - - case TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE: - if ( ( DG_MODE_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == getDGSubMode() ) ) - { - resMgmtTimer = getMSTimerCount(); - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE; - } - break; - - case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE: - if ( TRUE == didTimeout( resMgmtTimer, RESERVOIR_SETTLE_TIME_MS ) ) - { - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE; - } - break; - - case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE: - // Reservoir switch during treatment should only occur in this state (i.e. when DG is ready). - // Switch reservoirs when active reservoir is spent or full (i.e. we have pumped fill volume through dialyzer) and DG ready - if ( ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) || ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) ) - { - DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); - - // Signal dialysis sub-mode to capture baseline volume for next reservoir. - setStartReservoirVolume( inactiveRes ); - // Command DG to switch reservoirs - cmdSetDGActiveReservoir( inactiveRes ); - // Signal dialysis sub-mode to switch reservoirs - signalReservoirsSwitched(); - resUseVolumeMl = 0.0; - // Wait for used reservoir to settle - resMgmtTimer = getMSTimerCount(); - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; - } - break; - - case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE: - if ( TRUE == didTimeout( resMgmtTimer, RESERVOIR_SETTLE_TIME_MS ) ) - { - // Signal dialysis sub-mode to capture final volume of prior reservoir after settling. - setFinalReservoirVolume(); - // Reset to start state to restart drain, fill, switch process. - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; - } - break; - - default: - // TODO - s/w fault - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; - break; - } -} - /*********************************************************************//** * @brief * The getDGOpMode function gets the current DG operating mode. @@ -514,6 +331,18 @@ /*********************************************************************//** * @brief + * The getDGDisinfectsStates function returns the DG disinfects readings. + * @details Inputs: none + * @details Outputs: none + * @return the current DG disinfects readings + *************************************************************************/ +DG_DISINFECT_UI_STATES_T getDGDisinfectsStates( void ) +{ + return disinfectsStatus; +} + +/*********************************************************************//** + * @brief * The getDialysateTemperature function gets the latest dialysate temperature. * @details Inputs: dgDialysateTemp * @details Outputs: none @@ -526,14 +355,15 @@ /*********************************************************************//** * @brief - * The getDGDisinfectsStates function returns the DG disinfects readings. + * The getDGMixingRatios function returns the DG mixing ratios and the fill + * prep time. * @details Inputs: none - * @details Outputs: disinfectsStatus - * @return the current DG disinfects readings + * @details Outputs: none + * @return getDGMixingRatios which is the DG mixing ratios *************************************************************************/ -DG_DISINFECT_UI_STATES_T getDGDisinfectsStates( void ) +DG_MIXING_RATIOS_T getDGMixingRatios( void ) { - return disinfectsStatus; + return dgMixingRatios; } /*********************************************************************//** @@ -593,22 +423,6 @@ /*********************************************************************//** * @brief - * The setDGDialysateTemperatures function sets the latest temperature data - * reported by the DG. - * @details Inputs: none - * @details Outputs: dgPrimaryTemp, dgTrimmerTemp - * @param primaryHtrTemp Primary heater temperature reported by DG - * @param trimmerHtrTemp Trimmer heater temperature reported by DG - * @return none - *************************************************************************/ -void setDGDialysateTemperatures( F32 primaryHtrTemp, F32 trimmerHtrTemp ) -{ - dgPrimaryTemp = primaryHtrTemp; - dgTrimmerTemp = trimmerHtrTemp; -} - -/*********************************************************************//** - * @brief * The setDGReservoirsData function sets the latest reservoir data * reported by the DG. * @details Inputs: none @@ -701,21 +515,34 @@ memcpy( &disinfectsStatus, &states, sizeof(DG_DISINFECT_UI_STATES_T) ); } +/*********************************************************************//** + * @brief + * The setDGMixingRatios function sets the mixing ratios as well as the fill + * prep time upon a request from DG. + * @details Inputs: none + * @details Outputs: dgMixingRatios + * @param ratios the mixing ratios from DG + * @return none + *************************************************************************/ +void setDGMixingRatios( DG_MIXING_RATIOS_T ratios ) +{ + memcpy( &dgMixingRatios, &ratios, sizeof(DG_MIXING_RATIOS_T) ); +} + /*********************************************************************//** * @brief - * The cmdSetDGDialysateTargetTemps function sends a target dialysate - * temperature command message to the DG. + * The cmdSetDGDialysateHeatingParams function sends the dialysate heating + * parameters to DG. * @details Inputs: none - * @details Outputs: dgPrimaryTempSet, dgTrimmerTempSet - * @param primaryHtrTemp commanded target dialysate temperature for the primary heater - * @param trimmerHtrTemp commanded target dialysate temperature for the trimmer heater + * @details Outputs: dgTrimmerTempSet + * @param heatingParams Dialysate heating parameters to be sent to DG * @return none *************************************************************************/ -void cmdSetDGDialysateTargetTemps( F32 primaryHtrTemp, F32 trimmerHtrTemp ) +void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ) { - dgPrimaryTempSet = primaryHtrTemp; - dgTrimmerTempSet = trimmerHtrTemp; - sendDialysateTempTargetsToDG( dgPrimaryTempSet, dgTrimmerTempSet ); + dgTrimmerTempSet = heatingParams.trimmerTargetTemperature; + // TODO what should we do with the BOOL return of this function? + sendDialysateHeatingParamsToDG( &heatingParams ); } /*********************************************************************//** @@ -832,15 +659,16 @@ * The cmdStartDGFill function sends a fill command message to the DG. * @details Inputs: none * @details Outputs: fill command sent to DG. - * @param fillToVolMl volume (in mL) to fill inactive reservoir to + * @param fillToVolMl volume (in mL) to fill inactive reservoir to + * @param targetFlowLPM target flow rate in L/min * @return none *************************************************************************/ -void cmdStartDGFill( U32 fillToVolMl ) +void cmdStartDGFill( U32 fillToVolMl, F32 targetFlowLPM ) { dgCmdResp[ DG_CMD_START_FILL ].commandID = DG_CMD_NONE; dgReservoirFillVolumeTargetSet = fillToVolMl; - sendDGFillCommand( DG_CMD_START, fillToVolMl ); + sendDGFillCommand( DG_CMD_START, fillToVolMl, targetFlowLPM ); } /*********************************************************************//** @@ -855,7 +683,7 @@ dgCmdResp[ DG_CMD_STOP_FILL ].commandID = DG_CMD_NONE; dgReservoirFillVolumeTargetSet = 0; - sendDGFillCommand( DG_CMD_STOP, 0 ); + sendDGFillCommand( DG_CMD_STOP, 0, 0 ); } /*********************************************************************//** @@ -873,11 +701,11 @@ DRAIN_RESERVOIR_CMD_PAYLOAD_T payload; dgCmdResp[ DG_CMD_START_DRAIN ].commandID = DG_CMD_NONE; - payload.drainToVolumeML = drainToVolMl; - payload.tareLoadCells = tareLoadCell; - payload.rinseConcentrateLines = rinse; - payload.cmd = start; - dgReservoirDrainVolumeTargetSet = drainToVolMl; + payload.drainToVolumeML = drainToVolMl; + payload.tareLoadCells = tareLoadCell; + payload.rinseConcentrateLines = rinse; + payload.cmd = start; + dgReservoirDrainVolumeTargetSet = drainToVolMl; sendDGDrainCommand( &payload ); } @@ -986,12 +814,25 @@ { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_CHEM_DISINFECT ].commandID = DG_CMD_NONE; - sendDGStartChemicalDisinfectModeCommand( start ); } /*********************************************************************//** * @brief + * The cmdRequestDGConcentrateRatios function sends a request to DG to receive + * the concentrate ratios. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +void cmdRequestDGMixingRatios( void ) +{ + dgCmdResp[ DG_CMD_REQUEST_CONC_MIXING_RATIOS ].commandID = DG_CMD_NONE; + sendDGConcentrateMixingRatiosRequest(); +} + +/*********************************************************************//** + * @brief * The handleDGCommandResponse function processes the latest DG command response. * @details Inputs: none * @details Outputs: process command response from DG @@ -1094,6 +935,8 @@ #endif } +// ********** private functions ********** + /*********************************************************************//** * @brief * The checkDGRestart function checks to see if DG has restarted after started Index: firmware/App/Controllers/DGInterface.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -31,15 +31,21 @@ */ // ********** public definitions ********** + +#define DEFAULT_TARGET_FILL_FLOW_RATE_LPM 0.8 ///< Default target fill flow rate in L/min. +#define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. -#define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. -#define FILL_RESERVOIR_TO_VOLUME_ML 1700 ///< Fill reservoir to this volume (in mL) during treatment. -#define FILL_RESERVOIR_TO_VOLUME_LOW_FLOW_ML 1300 ///< Fill reservoir to this volume (in mL) during treatment if dialysate flow is slow. -#define SLOW_DIALYSATE_FLOW_ML_MIN 250 ///< Threshold for slow dialysate flow designation. - -/// Dialysate flow meter data struct. +/// DG Concentrate ratios data structure. typedef struct { + F32 acidMixingRatio; ///< Acid mixing ratio + F32 bicarbMixingRatio; ///< Bicarb mixing ratio + U32 timeFillPrepMS; ///< Fill prepare time in milliseconds +} DG_MIXING_RATIOS_T; + +/// Dialysate flow meter data structure. +typedef struct +{ F32 measuredDialysateFlowRate; ///< Dialysate flow meter rate average measurement } DIALYSATE_FLOW_METER_DATA_T; @@ -49,35 +55,44 @@ U32 resID; ///< Active reservoir ID U32 setFillToVolumeMl; ///< Reservoir set fill to target volume in ml U32 setDrainToVolumeMl; ///< Reservoir set drain to target volume in ml + U32 timeReservoirCycleMS; + U32 timeReservoirFill2SwitchMS; + F32 timeUFDecayMS; + F32 tempUFFill; + F32 tempReservoirUseActual; + F32 tempReservoirEndFill; + F32 tempAvgFill; + F32 tempLastFill; + F32 timereservoirFill; } DG_RESERVOIRS_DATA_PAYLOAD_T; /// Payload record structure for DG temperature sensors data message. typedef struct { - F32 inletPrimaryHeater; ///< Inlet primary heater temperature sensor - F32 outletPrimaryHeater; ///< Outlet primary heater temperature sensor - F32 conductivitySensor1; ///< Conductivity sensor 1 temperature sensor - F32 conductivitySensor2; ///< Conductivity sensor 2 temperature sensor - F32 outletRedundant; ///< Outlet redundant temperature sensor - F32 inletDialysate; ///< Inlet dialysate temperature sensor - F32 primaryHeaterThermocouple; ///< Primary heaters thermocouple sensor - F32 trimmerHeaterThermocouple; ///< Trimmer heater thermocouple sensor - F32 priamyHeaterColdjunction; ///< Primary heaters cold junction temperature sensor - F32 trimmerHeaterColdjunction; ///< Trimmer heater cold junction temperature sensor - F32 primaryHeaterInternal; ///< Primary heaters internal temperature (calculated from thermocouple and cold junction) - F32 trimmerHeaterInternal; ///< Trimmer heater internal temperature (calculated from thermocouple and cold junction) - F32 fpgaBoard; ///< FPGA board temperature sensor - F32 loadCellA1B1; ///< Load cell A1/B1 temperature sensor - F32 loadCellA2B2; ///< Load cell A2/B2 temperature sensor - F32 internalTHDORTD; ///< THDo RTD channel temperature sensor - F32 internalTDIRTD; ///< TDI RTD channel temperature sensor - F32 internalCondSnsrTemp; ///< Conductivity Sensor internal temperature sensor - U32 primaryThermoCoupleRaw; ///< Primary heaters thermocouple raw ADC value - U32 primaryColdjuncRaw; ///< Primary heaters cold junction raw ADC value - U32 trimmerThermoCoupleRaw; ///< Trimmer heater thermocouple raw ADC value - U32 trimmerColdjuncRaw; ///< Trimmer heater cold junction raw ADC value - S32 cond1Raw; ///< Conductivity sensor 1 raw temperature ADC value - S32 cond2Raw; ///< Conductivity sensor 2 raw temperature ADC value + F32 TPi; ///< Inlet primary heaters temperature sensor + F32 TPo; ///< Outlet primary heaters temperature sensor + F32 TD1; ///< Conductivity sensor 1 temperature sensor + F32 TD2; ///< Conductivity sensor 2 temperature sensor + F32 TRo; ///< Outlet redundant temperature sensor + F32 TDi; ///< Inlet dialysate temperature sensor + F32 HtrPrimThermo; ///< Primary heaters internal temperature sensor + F32 HtrTrimThermo; ///< Trimmer heater internal temperature sensor + F32 HtrPrimColdJunc; ///< Primary heaters cold junction temperature sensor + F32 HtrTrimColdJunc; ///< Trimmer heater cold junction temperature sensor + F32 HtrPrimInternal; ///< Primary heaters internal temperature + F32 HtrTrimInternal; ///< Trimmer heater internal temperature + F32 DGBoardTemp; ///< DG board temperature + F32 ResOneLoadCellTemp; ///< Reservoir 1 load cell sensor temperature + F32 ResTwoLoadCellTemp; ///< Reservoir 2 load cell sensor temperature + F32 THDoInternalTemp; ///< THDo RTD channel temperature sensor + F32 TDiInternalTemp; ///< TDI RTD channel temperature sensor + F32 internalCondSnsrTemp; ///< Conductivity Sensor internal temperature sensor + U32 primaryThermoCoupleRaw; ///< Primary heaters thermocouple raw ADC value + U32 primaryColdjuncRaw; ///< Primary heaters cold junction raw ADC value + U32 trimmerThermoCoupleRaw; ///< Trimmer heater thermocouple raw ADC value + U32 trimmerColdjuncRaw; ///< Trimmer heater cold junction raw ADC value + S32 cond1Raw; ///< Conductivity sensor 1 raw temperature ADC value + S32 cond2Raw; ///< Conductivity sensor 2 raw temperature ADC value } TEMPERATURE_SENSORS_DATA_T; /// Payload record structure for a drain reservoir command message. @@ -105,15 +120,23 @@ U32 flushUIState; ///< DG flush UI state } DG_DISINFECT_UI_STATES_T; +/// Dialysate heating parameters +typedef struct +{ + F32 trimmerTargetTemperature; + U32 timeReservoirCycleMS; + F32 timeReservoirFillMS; + U32 timeReservoirWait2SwitchMS; + F32 dialysateFlowLPM; +} DG_CMD_DIALYSATE_HEATING_PARAMS_T; + // ********** public function prototypes ********** void initDGInterface( void ); void execDGInterfaceMonitor( void ); -void initTreatmentReservoirMgmt( void ); void dialysisResumed( void ); -void execTreatmentReservoirMgmt( void ); DG_OP_MODE_T getDGOpMode( void ); U32 getDGSubMode( void ); @@ -125,23 +148,24 @@ F32 getLoadCellWeight( LOAD_CELL_ID_T loadCellID ); F32 getReservoirWeight( DG_RESERVOIR_ID_T resID ); F32 getReservoirWeightLargeFilter( DG_RESERVOIR_ID_T resID ); -F32 getDialysateTemperature( void ); DG_DISINFECT_UI_STATES_T getDGDisinfectsStates( void ); +F32 getDialysateTemperature( void ); +DG_MIXING_RATIOS_T getDGMixingRatios( void ); void setDGOpMode( U32 opMode, U32 subMode ); void setDialysateTemperatureReadings( F32 temp1, F32 temp2 ); -void setDGDialysateTemperatures( F32 primaryHtrTemp, F32 trimmerHtrTemp ); void setDGReservoirsData( DG_RESERVOIR_ID_T resID, U32 fillVol, U32 drainVol ); void setDialysateFlowData( F32 flowRate ); void setNewLoadCellReadings( F32 res1Primary, F32 res1Backup, F32 res2Primary, F32 res2Backup ); void setDGDisinfectsStates( DG_DISINFECT_UI_STATES_T states ); +void setDGMixingRatios( DG_MIXING_RATIOS_T ratios ); -void cmdSetDGDialysateTargetTemps( F32 primaryHtrTemp, F32 trimmerHtrTemp ); +void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ); void cmdStartDG( void ); void cmdStopDG( void ); void cmdSetDGActiveReservoir( DG_RESERVOIR_ID_T resID ); void cmdChangeDGValveSetting( DG_VALVE_SETTING_ID_T valveSettingID ); -void cmdStartDGFill( U32 fillToVolMl ); +void cmdStartDGFill( U32 fillToVolMl, F32 targetFlowLPM ); void cmdStopDGFill( void ); void cmdStartDGDrain( U32 drainToVolMl, BOOL tareLoadCell, BOOL rinse, BOOL start ); void cmdStartDGTrimmerHeater( void ); @@ -153,6 +177,7 @@ void cmdStopDGHeatDisinfect( void ); void cmdStartDGChemicalDisinfect( void ); void cmdStopDGChemicalDisinfect( void ); +void cmdRequestDGMixingRatios( void ); void handleDGCommandResponse( DG_CMD_RESPONSE_T *dgCmdRespPtr ); BOOL getDGCommandResponse( U32 commandID, DG_CMD_RESPONSE_T *cmdRespPtr ); Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -90,25 +90,27 @@ #define DIP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DIP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor. -#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000193 ///< ~52 BP motor RPM = 1% PWM duty cycle +#define DIAL_IN_PUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref V may be different). +#define DIAL_IN_PUMP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. + +///< Macro converts a 12-bit ADC reading to a signed 16-bit value. +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DIAL_IN_PUMP_ADC_ZERO ) + +#define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor (3500 RPM/1998 counts). +#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 BP motor RPM = 1% PWM duty cycle #define DIP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialIn pump motor. #define DIP_REV_PER_LITER 146.84 ///< Rotor revolutions per liter. /// Macro converts flow rate to motor RPM. #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_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. -/// Macro converts flow rate to estimate PWM needed to achieve it. // TODO - I added 1.2 gain based on empirical data -#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 * 1.2 + DIP_PWM_ZERO_OFFSET ) + +/// Macro converts flow rate to estimate PWM needed to achieve it. +#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 ) /// Conversion from PWM duty cycle % to commanded pump motor speed. #define DIP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DIP_PWM_ZERO_OFFSET) * 4000.0 ) -#define DIAL_IN_PUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref V may be different). -#define DIAL_IN_PUMP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. -///< Macro converts a 12-bit ADC reading to a signed 16-bit value. -#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DIAL_IN_PUMP_ADC_ZERO ) - /// Measured dialIn flow is filtered w/ moving average. #define SIZE_OF_ROLLING_AVG 10 @@ -220,7 +222,7 @@ { U32 i; - stopDialInPump(); + signalDialInPumpHardStop(); setDialInPumpDirection( MOTOR_DIR_FORWARD ); // Zero rolling flow average buffer @@ -260,54 +262,60 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isDialInPumpOn ) || ( 0 == flowRate ) || ( dir == dialInPumpDirectionSet ) ) { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetDialInFlowRate ) || ( mode != dialInPumpControlMode ) ) + { #ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) + // Verify flow rate + if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) #endif - { - resetDialInFlowMovingAverage(); - targetDialInFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); - dialInPumpDirection = dir; - dialInPumpControlMode = mode; - // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed - dialInPumpPWMDutyCyclePct = DIP_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%) - - switch ( dialInPumpState ) { - case DIAL_IN_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp - if ( dialInPumpPWMDutyCyclePct < dialInPumpPWMDutyCyclePctSet ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; - } - break; - case DIAL_IN_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp - if ( dialInPumpPWMDutyCyclePct > dialInPumpPWMDutyCyclePctSet ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; - } - break; - case DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction - if ( dialInPumpPWMDutyCyclePctSet > dialInPumpPWMDutyCyclePct ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; - } - else - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; - } - break; - default: - // Ok - not all states need to be handled here - break; + resetDialInFlowMovingAverage(); + targetDialInFlowRate = dirFlowRate; + dialInPumpDirection = dir; + dialInPumpControlMode = mode; + // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed + dialInPumpPWMDutyCyclePct = DIP_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%) + + switch ( dialInPumpState ) + { + case DIAL_IN_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( dialInPumpPWMDutyCyclePct < dialInPumpPWMDutyCyclePctSet ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; + } + break; + case DIAL_IN_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( dialInPumpPWMDutyCyclePct > dialInPumpPWMDutyCyclePctSet ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; + } + break; + case DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( dialInPumpPWMDutyCyclePctSet > dialInPumpPWMDutyCyclePct ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; + } + else + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; + } + break; + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; } - result = TRUE; - } #ifndef NO_PUMP_FLOW_LIMITS - else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, flowRate ) - } -#endif + else // Requested flow rate too high + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, flowRate ) + } +#endif + } } return result; @@ -565,7 +573,7 @@ // Have we essentially reached zero speed if ( dialInPumpPWMDutyCyclePctSet < (MAX_DIAL_IN_PUMP_PWM_STEP_DN_CHANGE + DIP_PWM_ZERO_OFFSET) ) { - stopDialInPump(); + signalDialInPumpHardStop(); result = DIAL_IN_PUMP_OFF_STATE; } // Have we reached end of ramp down? @@ -612,7 +620,8 @@ newPWM = runPIController( PI_CONTROLLER_ID_DIALYSATE_FLOW, tgtFlow, actFlow ); dialInPumpPWMDutyCyclePctSet = newPWM; - setDialInPumpControlSignalPWM( newPWM ); + setDialInPumpControlSignalPWM( newPWM ); + signalDialOutControl(); } dipControlTimerCounter = 0; } @@ -975,7 +984,9 @@ if ( lastDialInPumpDirectionCount != dirErrorCnt ) { lastDialInPumpDirectionCount = dirErrorCnt; +#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_INLET_PUMP ) +#endif } #endif Index: firmware/App/Controllers/DialOutFlow.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -21,16 +21,17 @@ #include "gio.h" #include "mibspi.h" +#include "DialOutFlow.h" #include "FPGA.h" #include "InternalADC.h" +#include "ModeTreatment.h" #include "OperationModes.h" #include "PIControllers.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" -#include "DialOutFlow.h" /** * @addtogroup DialysateOutlet @@ -41,6 +42,8 @@ /// Interval (ms/task time) at which the dialysate outlet pump data is published on the CAN bus. #define DIAL_OUT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) +/// Interval (ms/task time) at which the dialysate outlet flow is filtered. +#define DIAL_OUT_FILTER_INTERVAL ( 100 / TASK_PRIORITY_INTERVAL ) #define MAX_DIAL_OUT_FLOW_RATE 650 ///< Maximum dialysate outlet pump flow rate in mL/min. #define MIN_DIAL_OUT_FLOW_RATE 100 ///< Minimum dialysate outlet pump flow rate in mL/min. @@ -52,18 +55,21 @@ #define MAX_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL 0.4 ///< Maximum PWM offset (added to DPi PWM duty cycle). #define MIN_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL -0.4 ///< Minimum PWM offset (added to DPi PWM duty cycle). -#define DOP_CONTROL_INTERVAL_SEC 5 ///< Dialysate outlet pump control interval (in seconds). -/// Interval (ms/task time) at which the dialysate outlet pump is controlled. -static const U32 DOP_CONTROL_INTERVAL = ( DOP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); -#define DOP_P_COEFFICIENT 0.0010 ///< P term for dialysate outlet pump control. -#define DOP_I_COEFFICIENT 0.0001 ///< I term for dialysate outlet pump control. +#define P_VOL 0.001 ///< P term for volume error feedback into dialysate outlet pump control. +#define P_UF 0.001 ///< P term for UF rate error feedback into dialysate outlet pump control. +#define P_CORR 0.1666 ///< P term for volume error feedback into dialysate outlet pump flow estimate correction offset. +#define RPM_2_ML_MIN_CONVERSION 0.215964 ///< Conversion factor for estimating flow rate from pump motor RPM. +#define SIZE_OF_ROLLING_AVG 100 ///< Number of samples in DPo flow estimation moving average. + #define DOP_HOME_RATE 100 ///< Target pump speed (in estimate mL/min) for homing. #define DOP_HOME_TIMEOUT_MS 10000 ///< Maximum time allowed for homing to complete (in ms). + /// Interval (ms/task time) at which the blood pump speed is calculated (every 40 ms). #define DOP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) /// Number of hall sensor counts kept in buffer to hold last 1 second of count data. #define DOP_SPEED_CALC_BUFFER__LEN ( 1000 / DOP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) + #define DOP_HALL_EDGE_COUNTS_PER_REV 48 ///< Number of hall sensor edge counts per motor revolution. #define DOP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0 ///< Maximum motor speed (RPM) while motor is commanded off. @@ -83,19 +89,19 @@ #define DOP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DOP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define DOP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor. -#define DOP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000193 ///< ~52 BP motor RPM = 1% PWM duty cycle -#define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. #define DOP_ADC_FULL_SCALE_V 3.0 ///< DPo analog signals are 0-3V (while int. ADC ref V may be different). #define DOP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. #define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DOP_ADC_ZERO ) ///< Macro converts a 12-bit ADC reading to a signed 16-bit value. +#define DOP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor (3500 RPM/1998 counts). +#define DOP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 BP motor RPM = 1% PWM duty cycle +#define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. -/*** setDialOutFlowRxTotalVolumeAndRxTime ***/ -#define DOP_REV_PER_LITER 144.7 ///< Rotor revolutions per liter. +#define DOP_REV_PER_LITER 146.84 ///< Rotor revolutions per liter. #define DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DOP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to pump motor RPM. #define DOP_GEAR_RATIO 32.0 ///< Pump motor to pump gear ratio. #define DOP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. + /// Macro converts a flow rate to an estimated PWM duty cycle %. #define DOP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DOP_GEAR_RATIO * DOP_MOTOR_RPM_TO_PWM_DC_FACTOR + DOP_PWM_ZERO_OFFSET ) /// Conversion from PWM duty cycle % to commanded pump motor speed. @@ -150,12 +156,20 @@ static OVERRIDE_F32_T dialOutPumpMCCurrentmA = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump motor controller current. static OVERRIDE_F32_T dialOutPumpRotorSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump rotor speed. static OVERRIDE_F32_T dialOutPumpSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump motor speed. -#if 1 // TODO - remove test code -static F32 ufMeasuredRate = 0.0; -static F32 prevMeasuredVolumes[2] = { 0.0, 0.0 }; -#endif -static U32 dopControlTimerCounter = 0; ///< Timer counter to determine when to control dialysate outlet pump. +static F32 offsetPWMDutyCyclePct = 0.0; ///< PWM duty cycle percentage offset to add to inlet pump duty cycle for UF control. +static F32 dopMeasuredRate = 0.0; ///< Estimated flow rate for dialysate outlet pump. +static F32 ufMeasuredRate = 0.0; ///< Calculated UF flow rate from measured dialysate flow rate subtracted from estimated dialysate outlet flow rate. +static F32 dopRateCorrectionOffset = 0.0; ///< Correction offset for estimated flow rate for dialysate outlet pump. + +static U32 flowFilterTimerCtr = 0; ///< Timer counter for determining when to add a new sample to the moving average. +static F64 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 F64 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average. +static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer. + +static BOOL dopControlSignal = FALSE; ///< Control signal for syncing UF control to follow control interval of dialysate inlet pump. + static U32 dopCurrErrorDurationCtr = 0; ///< Timer counter for motor current error persistence. static U32 dopRotorRevStartTime = 0; ///< Dialysate outlet pump rotor rotation start time (in ms) @@ -193,6 +207,9 @@ static void checkDialOutPumpSpeeds( void ); static void checkDialOutPumpMCCurrent( void ); +static void resetDialOutFlowMovingAverage( void ); +static void filterDialOutFlowReadings( F64 flow ); + /*********************************************************************//** * @brief * The initDialOutFlow function initializes the DialOutFlow module. @@ -204,7 +221,7 @@ { U32 i; - stopDialOutPump(); + signalDialOutPumpHardStop(); setDialOutPumpDirection( MOTOR_DIR_FORWARD ); // Zero motor hall sensors counts buffer @@ -214,9 +231,10 @@ dopLastMotorHallSensorCounts[ i ] = 0; } - // Initialize dialysate outlet flow PI controller - initializePIController( PI_CONTROLLER_ID_ULTRAFILTRATION, 0.0, DOP_P_COEFFICIENT, DOP_I_COEFFICIENT, - MIN_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL, MAX_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL ); + dopMeasuredRate = 0.0; + ufMeasuredRate = 0.0; + dopRateCorrectionOffset = 40.0; // TODO - set to 0.0 when we have a better dop flow estimate. + resetDialOutFlowMovingAverage(); } /*********************************************************************//** @@ -237,56 +255,62 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isDialOutPumpOn ) || ( 0 == flowRate ) || ( dir == dialOutPumpDirectionSet ) ) { + F32 pwmDC = DOP_PWM_FROM_ML_PER_MIN( (F32)flowRate ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( fabs( pwmDC - dialOutPumpPWMDutyCyclePct ) > NEARLY_ZERO ) || ( mode != dialOutPumpControlMode ) ) + { #ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) + // Verify flow rate + if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) #endif - { - F32 adjFlow = (F32)flowRate; - - lastGivenRate = flowRate; - dialOutPumpDirection = dir; - dialOutPumpControlMode = mode; - // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed - dialOutPumpPWMDutyCyclePct = DOP_PWM_FROM_ML_PER_MIN(adjFlow); - dialOutPumpPWMDutyCyclePct = MIN( dialOutPumpPWMDutyCyclePct, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); - - switch ( dialOutPumpState ) { - case DIAL_OUT_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp - if ( dialOutPumpPWMDutyCyclePct < dialOutPumpPWMDutyCyclePctSet ) - { - dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; - } - break; - case DIAL_OUT_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp - if ( dialOutPumpPWMDutyCyclePct > dialOutPumpPWMDutyCyclePctSet ) - { - dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; - } - break; - case DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction - if ( dialOutPumpPWMDutyCyclePctSet > dialOutPumpPWMDutyCyclePct ) - { - dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; - } - else - { - dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; - } - break; - default: - // Ok - not all states need to be handled here - break; + resetDialOutFlowMovingAverage(); + dopControlSignal = FALSE; + lastGivenRate = flowRate; + dialOutPumpDirection = dir; + dialOutPumpControlMode = mode; + // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed + dialOutPumpPWMDutyCyclePct = pwmDC; + dialOutPumpPWMDutyCyclePct = MIN( dialOutPumpPWMDutyCyclePct, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); + + switch ( dialOutPumpState ) + { + case DIAL_OUT_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( dialOutPumpPWMDutyCyclePct < dialOutPumpPWMDutyCyclePctSet ) + { + dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; + } + break; + case DIAL_OUT_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( dialOutPumpPWMDutyCyclePct > dialOutPumpPWMDutyCyclePctSet ) + { + dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; + } + break; + case DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( dialOutPumpPWMDutyCyclePctSet > dialOutPumpPWMDutyCyclePct ) + { + dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; + } + else + { + dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; + } + break; + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; } - result = TRUE; - } #ifndef NO_PUMP_FLOW_LIMITS - else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) - } + else // Requested flow rate too high + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) + } #endif + } } return result; @@ -322,8 +346,7 @@ stopDialOutPump(); dialOutPumpState = DIAL_OUT_PUMP_OFF_STATE; dialOutPumpPWMDutyCyclePct = 0.0; - dopControlTimerCounter = 0; - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); + resetDialOutFlowMovingAverage(); } /*********************************************************************//** @@ -354,6 +377,56 @@ /*********************************************************************//** * @brief + * The signalDialOutControl function signals the dialysate outlet pump to + * perform a control. Call this function when dialysate inlet pump control + * has completed. + * @details Inputs: none + * @details Outputs: dopControlSignal + * @return none + *************************************************************************/ +void signalDialOutControl( void ) +{ + dopControlSignal = TRUE; +} + +/*********************************************************************//** + * @brief + * The resetDialOutFlowMovingAverage function resets the properties of the + * dialysate outlet flow moving average sample buffer. + * @details Inputs: none + * @details Outputs: flowReadingsTotal, flowReadingsIdx, flowReadingsCount all set to zero. + * @return none + *************************************************************************/ +static void resetDialOutFlowMovingAverage( void ) +{ + flowReadingsIdx = 0; + flowReadingsCount = 0; + flowReadingsTotal = 0.0; + offsetPWMDutyCyclePct = 0.0; +} + +/*********************************************************************//** + * @brief + * The filterDialOutFlowReadings function adds a new flow sample to the filter. + * @details Inputs: none + * @details Outputs: flowReadings[], flowReadingsIdx, flowReadingsCount, flowReadingsTotal + * @return none + *************************************************************************/ +static void filterDialOutFlowReadings( F64 flow ) +{ + 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 ); + dopMeasuredRate = (F32)( flowReadingsTotal / (F64)flowReadingsCount ) + dopRateCorrectionOffset; +} + +/*********************************************************************//** + * @brief * The homeDialOutPump function initiates a dialysate outlet pump home operation. * @details Inputs: dialOutPumpState * @details Outputs: dopStopAtHomePosition, dopHomeStartTime, dialysate outlet pump started (slow) @@ -406,6 +479,16 @@ // Calculate dialysate outlet pump motor speed/direction from hall sensor count updateDialOutPumpSpeedAndDirectionFromHallSensors(); + // Filter estimated dialysate out flow rate and calculate UF rate + if ( ++flowFilterTimerCtr >= DIAL_OUT_FILTER_INTERVAL ) + { + flowFilterTimerCtr = 0; + // Calculate DPo flow in mL/min + filterDialOutFlowReadings( getMeasuredDialOutPumpMCSpeed() * RPM_2_ML_MIN_CONVERSION ); + // Calculate UF flow in mL/min + ufMeasuredRate = dopMeasuredRate - getMeasuredDialInFlowRate(); + } + // Do not start enforcing checks until out of init/POST mode if ( getCurrentOperationMode() != MODE_INIT ) { @@ -512,17 +595,9 @@ else if ( dialOutPumpPWMDutyCyclePctSet >= dialOutPumpPWMDutyCyclePct ) { dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; - if ( dialOutPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet ); - } - else - { // Closed loop UF control is only controlling offset from DPi PWM - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet - getDialInPumpPWMDutyCyclePct( TRUE ) ); - } dialOutPumpControlModeSet = dialOutPumpControlMode; + resetDialOutFlowMovingAverage(); setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); - dopControlTimerCounter = 0; result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp up @@ -557,17 +632,9 @@ else if ( dialOutPumpPWMDutyCyclePctSet <= dialOutPumpPWMDutyCyclePct ) { dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; - if ( ( dialOutPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) || ( 0 == lastGivenRate ) ) - { - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet ); - } - else - { // Closed loop UF control is only controlling offset from DPi PWM - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet - getDialInPumpPWMDutyCyclePct( TRUE ) ); - } dialOutPumpControlModeSet = dialOutPumpControlMode; + resetDialOutFlowMovingAverage(); setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); - dopControlTimerCounter = 0; result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp down @@ -592,23 +659,23 @@ { DIAL_OUT_PUMP_STATE_T result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; - // Control at set interval - if ( ++dopControlTimerCounter >= DOP_CONTROL_INTERVAL ) + // Control when signalled (sync'd with dialysate inlet pump control - we want this control to follow inlet pump) + if ( TRUE == dopControlSignal ) { if ( dialOutPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) { F32 refVol = getTotalTargetDialOutUFVolumeInMl(); F32 totVol = getTotalMeasuredUFVolumeInMl(); - F32 offsetPWMDutyCyclePct; + F32 volErr = refVol - totVol; + F32 ufrErr = getCurrentUFSetRate() - ufMeasuredRate; -#if 1 // TODO - remove test code - ufMeasuredRate = ( totVol - prevMeasuredVolumes[1] ) * 6.0; // calculate UF rate based on change in volume over last 10 seconds - prevMeasuredVolumes[1] = prevMeasuredVolumes[0]; // update last 2 volumes for next time - prevMeasuredVolumes[0] = totVol; -#endif + dopControlSignal = FALSE; - // Get new PWM offset from PI controller - offsetPWMDutyCyclePct = runPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, refVol, totVol ); + dopRateCorrectionOffset += ( ( totVol - refVol ) * P_CORR ); + + offsetPWMDutyCyclePct += volErr * P_VOL; + offsetPWMDutyCyclePct += ( ufrErr * P_UF ); + // Add PWM offset to DPi PWM mirror for our new DPo PWM dialOutPumpPWMDutyCyclePctSet = getDialInPumpPWMDutyCyclePct( FALSE ) + offsetPWMDutyCyclePct; // Limit PWM range @@ -617,7 +684,6 @@ // Apply new PWM to DPo pump setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } - dopControlTimerCounter = 0; } return result; @@ -712,14 +778,13 @@ dialOutBroadCastVariables.refUFVolMl = getTotalTargetDialOutUFVolumeInMl(); dialOutBroadCastVariables.measUFVolMl = getTotalMeasuredUFVolumeInMl(); dialOutBroadCastVariables.measRotSpdRPM = getMeasuredDialOutPumpRotorSpeed(); -#if 1 // TODO - remove test code - dialOutBroadCastVariables.measSpdRPM = ufMeasuredRate; -#else dialOutBroadCastVariables.measSpdRPM = getMeasuredDialOutPumpSpeed(); -#endif dialOutBroadCastVariables.measMCSpdRPM = getMeasuredDialOutPumpMCSpeed(); dialOutBroadCastVariables.measMCCurrmA = getMeasuredDialOutPumpMCCurrent(); dialOutBroadCastVariables.setPWMpct = dialOutPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + dialOutBroadCastVariables.dopCorrOffset = dopRateCorrectionOffset; + dialOutBroadCastVariables.dopCalcRate = dopMeasuredRate; + dialOutBroadCastVariables.ufCalcRate = ufMeasuredRate; broadcastData( MSG_ID_DIALYSATE_OUT_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&dialOutBroadCastVariables, sizeof( DIAL_OUT_FLOW_DATA_T ) ); dialOutFlowDataPublicationTimerCounter = 0; @@ -811,7 +876,9 @@ if ( lastDialOutPumpDirectionCount != dirErrorCnt ) { lastDialOutPumpDirectionCount = dirErrorCnt; +#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_OUTLET_PUMP ) +#endif } dopMCDir = ( getMeasuredDialOutPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); Index: firmware/App/Controllers/DialOutFlow.h =================================================================== diff -u -rd4811e9467b4bbafe7012ece67365a03190af00a -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/DialOutFlow.h (.../DialOutFlow.h) (revision d4811e9467b4bbafe7012ece67365a03190af00a) +++ firmware/App/Controllers/DialOutFlow.h (.../DialOutFlow.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/Fans.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/Fans.c (.../Fans.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/Fans.c (.../Fans.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -7,8 +7,8 @@ * * @file Fans.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 15-Sep-2021 * * @author (original) Dara Navaei * @date (original) 04-Aug-2021 @@ -73,29 +73,32 @@ static FAN_STATUS_T fansStatus; ///< Fans status. static FANS_EXEC_STATES_T fansExecState = FANS_EXEC_STATE_WAIT_FOR_POST_STATE; ///< Fans exec state. -static U32 fansControlCounter = 0; ///< Fans control interval counter. -static U32 fansPublishCounter = 0; ///< Fans data publish interval counter. -static U32 fansMonitorCounter = 0; ///< Fans monitor interval counter. +static U32 fansControlCounter = 0; ///< Fans control interval counter. +static U32 fansPublishCounter = 0; ///< Fans data publish interval counter. +static U32 fansMonitorCounter = 0; ///< Fans monitor interval counter. static BOOL isPOSTComplete = FALSE; ///< Flag that indicates whether POST is complete or not. static BOOL hasAlarmBeenRaised = FALSE; ///< Flag that indicates whether RPM out of range alarm has been raised once. -static U32 rpmAlarmStartTimer = 0; ///< RPM out of range alarm start timer when the alarm is raised. +static OVERRIDE_U32_T rpmAlarmStartTimeOffset = { 0, 0, 0, 0}; ///< RPM out of range alarm start time offset. +static U32 rpmAlarmStartTime = 0; ///< RPM alarm start time. /// Temperature to duty cycle conversion slope (duty cycle not in percent) static const F32 SLOPE = ( FANS_MAX_DUTY_CYCLE - FANS_MIN_DUTY_CYCLE ) / ( MAX_ALLOWED_AMBINET_TEMPERATURE - MIN_ALLOWED_AMBIENT_TEMPERATURE ); /// FGPA Toggle to RPM conversion coefficient static const F32 TOGGLE_PERIOD_2_RPM_COEFFICIENT = SEC_PER_MIN / ( TOGGLE_PERIOD_RESOLUTION_SECONDS * ROTATIONAL_TO_TOGGLE_PERIOD_CONVERSION ); -static OVERRIDE_U32_T fansPublishInterval = { FANS_DATA_PUBLISH_INTERVAL, FANS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Fans publish time interval override +static OVERRIDE_U32_T fansPublishInterval = { FANS_DATA_PUBLISH_INTERVAL, + FANS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Fans publish time interval override static FANS_EXEC_STATES_T handleExecStateWaitForPOST( void ); static FANS_EXEC_STATES_T handleExecStateRun( void ); static void setInletFansDutyCycle( F32 pwm ); -static F32 getMaximumTemperature( void ); +static F32 getMaximumTemperature( void ); static void convertTogglePeriod2RPM( void ); static void monitorFans( void ); -static U32 getPublishFansDataInterval( void ); +static U32 getPublishFansDataInterval( void ); +static U32 getRPMAlarmStartTimeOffset( void ); static void publishFansData( void ); /*********************************************************************//** @@ -104,21 +107,25 @@ * @details Inputs: none * @details Outputs: fansExecState, fansMonitorCounter, fansControlCounter, * fansPublishCounter, isPOSTComplete, hasAlarmBeenRaised, fansStatus, - * rpmAlarmStartTimer + * rpmAlarmStartTime, rpmAlarmStartTimeOffset * @return none *************************************************************************/ void initFans( void ) { FAN_NAMES_T fan; // Initialize the variables - fansExecState = FANS_EXEC_STATE_WAIT_FOR_POST_STATE; - fansControlCounter = 0; - fansPublishCounter = 0; - fansMonitorCounter = 0; - isPOSTComplete = FALSE; - hasAlarmBeenRaised = FALSE; - rpmAlarmStartTimer = 0; + fansExecState = FANS_EXEC_STATE_WAIT_FOR_POST_STATE; + fansControlCounter = 0; + fansPublishCounter = 0; + fansMonitorCounter = 0; + isPOSTComplete = FALSE; + hasAlarmBeenRaised = FALSE; + rpmAlarmStartTime = 0; + rpmAlarmStartTimeOffset.data = 0; + rpmAlarmStartTimeOffset.ovData = 0; + rpmAlarmStartTimeOffset.ovInitData = 0; + rpmAlarmStartTimeOffset.override = 0; // Initialize the fans for ( fan = FAN_INLET_1; fan < NUM_OF_FANS_NAMES; fan++ ) @@ -186,6 +193,7 @@ // Monitor the RPM of the fans monitorFans(); + // Check for the publication time publishFansData(); } @@ -348,18 +356,18 @@ F32 maxTemperature = 0.0; - // NOTE: a for loop was not used because the venous pressure sensor's temperature + // NOTE: A for loop was not used because the venous pressure sensor's temperature // is not used as one of temperature values to decide the hottest temperature - temperature = getTemperatureValue( THERMISTOR_ONBOARD_NTC ); + temperature = getTemperatureValue( THERMISTOR_ONBOARD_NTC ); maxTemperature = ( temperature > maxTemperature ? temperature : maxTemperature ); - temperature = getTemperatureValue( THERMISTOR_POWER_SUPPLY_1 ); + temperature = getTemperatureValue( THERMISTOR_POWER_SUPPLY_1 ); maxTemperature = ( temperature > maxTemperature ? temperature : maxTemperature ); - temperature = getTemperatureValue( TEMPSENSOR_FPGA_BOARD_SENSOR ); + temperature = getTemperatureValue( TEMPSENSOR_FPGA_BOARD_SENSOR ); maxTemperature = ( temperature > maxTemperature ? temperature : maxTemperature ); - temperature = getTemperatureValue( TEMPSENSOR_PBA_ADC_SENSOR ); + temperature = getTemperatureValue( TEMPSENSOR_PBA_ADC_SENSOR ); maxTemperature = ( temperature > maxTemperature ? temperature : maxTemperature ); return maxTemperature; @@ -407,26 +415,27 @@ { if ( ++fansMonitorCounter >= FANS_MONITOR_INTERVAL_COUNT ) { - if ( FALSE == hasAlarmBeenRaised ) - { - FAN_NAMES_T fan; - BOOL isFanRPMOutOfRange = FALSE; - BOOL isAlarmTriggered = FALSE; - F32 rpm = 0.0; + FAN_NAMES_T fan; + BOOL isFanRPMOutOfRange = FALSE; + BOOL isAlarmTriggered = FALSE; + F32 rpm = 0.0; - // The RPM is expected to be 5500 @ 100% duty cycle - // The nominal RPM = duty cycle * 5500 / 1.0 - // The RPM tolerance is -25% to +50% of the nominal RPM - F32 fansNominalRPM = fansStatus.targetDutyCycle * FANS_MAX_ALLOWED_RPM; - F32 fansMinAllowedRPM = fansNominalRPM - ( fansNominalRPM * FANS_MIN_RPM_OUT_OF_RANGE_TOL ); - F32 fansMaxAllowedRPM = fansNominalRPM + ( fansNominalRPM * FANS_MAX_RPM_OUT_OF_RANGE_TOL ); + // The RPM is expected to be 5500 @ 100% duty cycle + // The nominal RPM = duty cycle * 5500 / 1.0 + // The RPM tolerance is -25% to +50% of the nominal RPM + F32 fansNominalRPM = fansStatus.targetDutyCycle * FANS_MAX_ALLOWED_RPM; + F32 fansMinAllowedRPM = fansNominalRPM - ( fansNominalRPM * FANS_MIN_RPM_OUT_OF_RANGE_TOL ); + F32 fansMaxAllowedRPM = fansNominalRPM + ( fansNominalRPM * FANS_MAX_RPM_OUT_OF_RANGE_TOL ); - for ( fan = FAN_INLET_1; fan < NUM_OF_FANS_NAMES; fan++ ) - { - rpm = getMeasuredFanRPM( fan ); - isFanRPMOutOfRange |= ( rpm < fansMinAllowedRPM ) || ( rpm > fansMaxAllowedRPM ); - } + // Loop through the fans and make sure the each of them have RPM in range + for ( fan = FAN_INLET_1; fan < NUM_OF_FANS_NAMES; fan++ ) + { + rpm = getMeasuredFanRPM( fan ); + isFanRPMOutOfRange |= ( ( rpm < fansMinAllowedRPM ) || ( rpm > fansMaxAllowedRPM ) ? TRUE : FALSE ); + } + if ( FALSE == hasAlarmBeenRaised ) + { isAlarmTriggered = isPersistentAlarmTriggered( ALARM_ID_HD_FAN_RPM_OUT_OF_RANGE, isFanRPMOutOfRange ); if ( TRUE == isAlarmTriggered ) @@ -435,27 +444,55 @@ // Set the alarm flag to TRUE hasAlarmBeenRaised = TRUE; } - // If the alarm has been raised but the time that the alarm has not been set, set the alarm start timer - if ( ( TRUE == hasAlarmBeenRaised ) && ( 0 == rpmAlarmStartTimer ) ) + // If the alarm has been raised but the start time of the alarm has not been set, set the alarm start timer + if ( ( TRUE == hasAlarmBeenRaised ) && ( 0 == rpmAlarmStartTime ) ) { - rpmAlarmStartTimer = getMSTimerCount(); + rpmAlarmStartTime = getMSTimerCount(); } } // If the alarm has been raised and the alarm has been silent for at least a day, set the flag to FALSE // This way, if the fans RPM are out of range the alarm will be raised again. This alarm is supposed to be raised - // and remain silent for a define period of time. - else if ( ( TRUE == hasAlarmBeenRaised ) && ( TRUE == didTimeout( rpmAlarmStartTimer, SECONDS_IN_A_DAY ) ) ) + // and remain silent for a defined period of time. + else if ( ( TRUE == hasAlarmBeenRaised ) && ( ( calcTimeSince( rpmAlarmStartTime ) + getRPMAlarmStartTimeOffset() ) >= SECONDS_IN_A_DAY * MS_PER_SECOND ) ) { hasAlarmBeenRaised = FALSE; - rpmAlarmStartTimer = 0; + rpmAlarmStartTime = 0; } + else + { + // If the alarm has been raised and 24 hours has not elapsed, check if the fans RPM is back in range again + // If the fans RPM is in range again, clear the alarm + if ( FALSE == isFanRPMOutOfRange ) + { + clearAlarmCondition( ALARM_ID_HD_FAN_RPM_OUT_OF_RANGE ); + } + } fansMonitorCounter = 0; } } /*********************************************************************//** * @brief + * The getRPMAlarmStartTimeOffset function gets the RPM alarm start time offset in MS. + * @details Inputs: rpmAlarmStartTimeOffset + * @details Outputs: none + * @return the RPM alarm start time offset + *************************************************************************/ +static U32 getRPMAlarmStartTimeOffset( void ) +{ + U32 startTime = rpmAlarmStartTimeOffset.data; + + if ( OVERRIDE_KEY == rpmAlarmStartTimeOffset.override ) + { + startTime = rpmAlarmStartTimeOffset.ovData; + } + + return startTime; +} + +/*********************************************************************//** + * @brief * The getPublishFansDataInterval function gets the fans data publish interval. * @details Inputs: fansPublishInterval * @details Outputs: none @@ -485,13 +522,14 @@ { if ( ++fansPublishCounter > getPublishFansDataInterval() ) { - FANS_DATA_T fansData; + FANS_DATA_T data; - fansData.fansDutyCycle = fansStatus.targetDutyCycle * FRACTION_TO_PERCENT_FACTOR; - fansData.fansTargetRPM = fansStatus.targetRPM; - fansData.fanInlet1RPM = getMeasuredFanRPM( FAN_INLET_1 ); + data.fansDutyCycle = fansStatus.targetDutyCycle * FRACTION_TO_PERCENT_FACTOR; + data.fansTargetRPM = fansStatus.targetRPM; + data.fanInlet1RPM = getMeasuredFanRPM( FAN_INLET_1 ); + data.rpmAlarmTimeOffset = getRPMAlarmStartTimeOffset(); - broadcastData( MSG_ID_HD_FANS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&fansData, sizeof( FANS_DATA_T ) ); + broadcastData( MSG_ID_HD_FANS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( FANS_DATA_T ) ); fansPublishCounter = 0; } @@ -601,5 +639,54 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetFanRPMAlarmStartTimeOffsetOverride function overrides the RPM alarm + * start time offset. + * @details Inputs: none + * @details Outputs: rpmAlarmStartTimeOffset + * @param hours hours to override + * @param minutes minutes to override + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 hours, U32 minutes ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + rpmAlarmStartTimeOffset.ovData = rpmAlarmStartTimeOffset.ovData + ( ( hours * MIN_PER_HOUR * SEC_PER_MIN ) + ( minutes * SEC_PER_MIN ) ) * MS_PER_SECOND; + rpmAlarmStartTimeOffset.override = OVERRIDE_KEY; + + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetFanRPMAlarmStartTimeOffsetOverride function resets the RPM alarm + * start time offset override. + * @details Inputs: none + * @details Outputs: rpmAlarmStartTimeOffset + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetFanRPMAlarmStartTimeOffsetOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + rpmAlarmStartTimeOffset.override = OVERRIDE_RESET; + rpmAlarmStartTimeOffset.ovData = 0; + rpmAlarmStartTimeOffset.data = 0; + + result = TRUE; + } + + return result; +} + /**@}*/ Index: firmware/App/Controllers/Fans.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/Fans.h (.../Fans.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/Fans.h (.../Fans.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -41,6 +41,7 @@ F32 fansDutyCycle; ///< Fans duty cycle F32 fansTargetRPM; ///< Fans target RPM F32 fanInlet1RPM; ///< Fan inlet 1 RPM + U32 rpmAlarmTimeOffset; } FANS_DATA_T; void initFans( void ); @@ -49,14 +50,17 @@ void execFans( void ); -F32 getMeasuredFanRPM( FAN_NAMES_T fan ); +F32 getMeasuredFanRPM( FAN_NAMES_T fan ); BOOL testSetFanPublishIntervalOverride( U32 value ); BOOL testResetFanPublishIntervalOverride( void ); BOOL testSetFanRPMOverride( U32 fanId, F32 rpm ); BOOL testResetFanRPMOverride( U32 fanId ); +BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 hours, U32 minutes ); +BOOL testResetFanRPMAlarmStartTimeOffsetOverride( void ); + /**@}*/ Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -363,15 +363,7 @@ // Check for stale arterial pressure reading if ( FALSE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr || artErrorCtr > 0 ) ) ) { -#ifndef PBA_ESTIMATION arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( (F32)(artPres) / ( ARTERIAL_PRESSURE_SENSITIVITY * ARTERIAL_PRESSURE_V_BIAS ) ) + getF32OverrideValue( &arterialPressureOffset ); -#else - // TODO - temporary test code - remove later - F32 artPres = -0.1146 * getMeasuredBloodPumpMCSpeed(); - artPres = MAX(-200.0,artPres); - artPres = MIN(0,artPres); - arterialPressure.data = artPres; -#endif } else { @@ -468,7 +460,7 @@ { F32 artPres = getFilteredArterialPressure(); -#ifndef DISABLE_PRESSURE_CHECKS +#ifndef DISABLE_ARTERIAL_PRESSURE_CHECK // Check arterial pressure is in range if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, ( artPres > ARTERIAL_PRESSURE_MAX_MMHG || artPres < ARTERIAL_PRESSURE_MIN_MMHG ) ) ) @@ -513,15 +505,15 @@ { F32 venPres = getFilteredVenousPressure(); -#ifndef DISABLE_PRESSURE_CHECKS - // Check arterial pressure is in range +#ifndef DISABLE_VENOUS_PRESSURE_CHECK + // Check venous pressure is in range if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres > VENOUS_PRESSURE_MAX_MMHG ) || TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres < VENOUS_PRESSURE_MIN_MMHG ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); } - // Check arterial pressure during treatment mode + // Check venous pressure during treatment mode if ( ( MODE_TREA == getCurrentOperationMode() ) && ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE ) ) { F32 venLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); @@ -576,11 +568,11 @@ if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) { signalBloodPumpHardStop(); // Stop pump immediately - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) + //SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) } else if ( bpOccl < ( OCCLUSION_CLEAR_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) { - clearAlarmCondition( ALARM_ID_OCCLUSION_BLOOD_PUMP ); + //clearAlarmCondition( ALARM_ID_OCCLUSION_BLOOD_PUMP ); } #endif } Index: firmware/App/Controllers/SyringePump.c =================================================================== diff -u -r946f42bfd6606dd3d771d9a4a7b50e5678469f62 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 946f42bfd6606dd3d771d9a4a7b50e5678469f62) +++ firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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 -r9ac7866cce73b5281c34626ab5903409778e2b19 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Drivers/Comm.c (.../Comm.c) (revision 9ac7866cce73b5281c34626ab5903409778e2b19) +++ firmware/App/Drivers/Comm.c (.../Comm.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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.h =================================================================== diff -u -r9ac7866cce73b5281c34626ab5903409778e2b19 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Drivers/Comm.h (.../Comm.h) (revision 9ac7866cce73b5281c34626ab5903409778e2b19) +++ firmware/App/Drivers/Comm.h (.../Comm.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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.c =================================================================== diff -u -r893b25a778d71b4d779ff14aa7361914f388e87e -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Drivers/InternalADC.c (.../InternalADC.c) (revision 893b25a778d71b4d779ff14aa7361914f388e87e) +++ firmware/App/Drivers/InternalADC.c (.../InternalADC.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/SafetyShutdown.c =================================================================== diff -u -rb3375bb1bc7910b7f45922d2eb4e55bb1dcc3c16 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Drivers/SafetyShutdown.c (.../SafetyShutdown.c) (revision b3375bb1bc7910b7f45922d2eb4e55bb1dcc3c16) +++ firmware/App/Drivers/SafetyShutdown.c (.../SafetyShutdown.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/HDCommon.h =================================================================== diff -u -rf1c099b79e0825afe54379577454518f7a134a73 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/HDCommon.h (.../HDCommon.h) (revision f1c099b79e0825afe54379577454518f7a134a73) +++ firmware/App/HDCommon.h (.../HDCommon.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -10,8 +10,8 @@ * @author (last) Sean Nash * @date (last) 12-Nov-2021 * -* @author (original) Sean -* @date (original) 27-Feb-2020 +* @author (original) Sean +* @date (original) 27-Feb-2020 * ***************************************************************************/ @@ -25,7 +25,7 @@ #define HD_VERSION_MAJOR 0 #define HD_VERSION_MINOR 6 #define HD_VERSION_MICRO 0 -#define HD_VERSION_BUILD 29 +#define HD_VERSION_BUILD 147 // ********** development build switches ********** @@ -49,18 +49,20 @@ // #define RUN_BP_OPEN_LOOP 1 // Run blood pump in open loop mode // #define RUN_DPI_OPEN_LOOP 1 // Run dialysate inlet pump in open loop mode #define WORN_OUT_CARTRIDGE 1 // Running with an old worn out cartridge (max wear) -// #define PBA_ESTIMATION 1 // Estimate arterial pressure rather than look at PBA sensor - #define DISABLE_MOTOR_CURRENT_CHECKS 1 // Do not error on HD pump current checks - #define DISABLE_PUMP_FLOW_CHECKS 1 // Do not error on HD pump flow checks - #define DISABLE_PUMP_SPEED_CHECKS 1 // Do not error on HD pump speed checks - #define DISABLE_PUMP_DIRECTION_CHECKS 1 // Do not error on HD pump direction checks - #define DISABLE_SYRINGE_PUMP 1 // Disable syringe pump functionality + #define PBA_ESTIMATION 1 // Estimate arterial pressure rather than look at PBA sensor +// #define DISABLE_MOTOR_CURRENT_CHECKS 1 // Do not error on HD pump current checks +// #define DISABLE_PUMP_FLOW_CHECKS 1 // Do not error on HD pump flow checks +// #define DISABLE_PUMP_SPEED_CHECKS 1 // Do not error on HD pump speed checks +// #define DISABLE_PUMP_DIRECTION_CHECKS 1 // Do not error on HD pump direction checks +// #define DISABLE_SYRINGE_PUMP 1 // Disable syringe pump functionality #define ALWAYS_ALLOW_SYRINGE_PUMP_CMDS 1 // Allow syringe pump commands at any time except when pump is busy #define DISABLE_PRESSURE_CHECKS 1 // Do not error on HD pressure checks + #define DISABLE_ARTERIAL_PRESSURE_CHECK 1 // Do not error on arterial pressure out of range + #define DISABLE_VENOUS_PRESSURE_CHECK 1 // Do not error on venous pressure out of range // #define DISABLE_UF_ALARMS 1 // Do not error on HD ultrafiltration checks #define DISABLE_DIALYSATE_TEMP_CHECK 1 // Disable dialysate temperature check -// #define DISABLE_VALVE_ALARMS 1 // Do not error on HD valve position - #define SKIP_CAL_CHECK 1 + #define DISABLE_VALVE_ALARMS 1 // Do not error on HD valve position + #define SKIP_CAL_CHECK 1 // // #define RUN_PUMPS_OPEN_LOOP 1 // BP and DPi pumps will be run open loop (no flow sensor feedback) // #define READ_FPGA_ASYNC_DATA 1 // Test build reads non-priority register page every other time // #define EMC_TEST_BUILD 1 // EMC test build - HD/DG run separately but connected, HD pumps toggle on/off w/ stop button @@ -75,18 +77,25 @@ #define ALLOW_1_MIN_TREATMENT_DURATION 1 // Allow user to change treatment duration to as low as 1 minute #define DISABLE_SYRINGE_PUMP_ALARMS 1 // Disable some syringe pump alarms that are triggering intermittently // #define NO_PUMP_FLOW_LIMITS 1 // Allow any commanded flow rate for peristaltic pumps -// #define DISABLE_BUBBLE_ALARMS 1 // Disable bubble alarms + #define DISABLE_BUBBLE_ALARMS 1 // Disable bubble alarms #define DISABLE_UI_POST_TEST 1 // Disable the UI POST // #define DISABLE_UI_COMM_TO_ALARM 1 // Disable UI comm timeouts + #define DISABLE_WD_AND_SFTY_POST_TESTS 1 // Disable watchdog and safety shutdown POST tests + #define DISABLE_ILLEGAL_AIR_TRAP_ALARM 1 // Disable illegal state for air trap alarm + #define SKIP_RESERVOIR_ALARMS 1 // Skip reservoir management alarms +// #define SKIP_RESERVOIR_ALARMS 1 // Skip reservoir management alarms + #define IGNORE_BLOOD_LEAK_SELF_TEST 1 // Ignore blood leak self test + // #define IGNORE_BLOOD_LEAK_ALARM 1 // Ignore blood leak alarm // Skip Pre-Treatment and get to treatment as soon as possible // #define SKIP_UI_INTERACTION 1 // Skip UI interaction. - #define SKIP_SAMPLE_WATER 1 // Skip pre-treatment sample water - #define SKIP_CONSUMABLE_TESTS 1 // Skip pre-treatment consumable Self-tests - #define SKIP_DRY_SELF_TESTS 1 // Skip pre-treatment dry self-tests +// #define SKIP_SAMPLE_WATER 1 // Skip pre-treatment sample water +// #define SKIP_CONSUMABLE_TESTS 1 // Skip pre-treatment consumable Self-tests +// #define SKIP_DRY_SELF_TESTS 1 // Skip pre-treatment dry self-tests // #define SKIP_PRIMING 1 // Skip Pre-treatment Prime // #define SKIP_WET_SELF_TESTS 1 // Skip Pre-treatment prime wet self-tests + #include #include #endif Index: firmware/App/Modes/BloodPrime.c =================================================================== diff -u -r42ce27a9c940f5fd8a858aca69cbe8dd635ccf8d -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 42ce27a9c940f5fd8a858aca69cbe8dd635ccf8d) +++ firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ConsumableSelfTest.c =================================================================== diff -u -r182a81ed78f66f05ef286e2456c6c86f5e4f3e28 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ConsumableSelfTest.c (.../ConsumableSelfTest.c) (revision 182a81ed78f66f05ef286e2456c6c86f5e4f3e28) +++ firmware/App/Modes/ConsumableSelfTest.c (.../ConsumableSelfTest.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/Dialysis.c =================================================================== diff -u -rd4670b91145b97cb5a4a35dea604bff6c849c62d -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision d4670b91145b97cb5a4a35dea604bff6c849c62d) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/Dialysis.h =================================================================== diff -u -r549119eae64732f124d22df66de4fc88c56193c0 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision 549119eae64732f124d22df66de4fc88c56193c0) +++ firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ModeInitPOST.c =================================================================== diff -u -r57131d8f8cfb3979f5f395d1152c6afd85d1d088 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 57131d8f8cfb3979f5f395d1152c6afd85d1d088) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ModePreTreat.c =================================================================== diff -u -rf3c8ef49b4bef41b606325e3db0e053a7a72d98f -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision f3c8ef49b4bef41b606325e3db0e053a7a72d98f) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ModeTreatment.c =================================================================== diff -u -r075210a84af3deede4bf07f83091f14aca6d12c9 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 075210a84af3deede4bf07f83091f14aca6d12c9) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ModeTreatment.h =================================================================== diff -u -r58afeb5a318882fa028894b51aefba526b2fb1f0 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 58afeb5a318882fa028894b51aefba526b2fb1f0) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/ModeTreatmentParams.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -140,6 +140,9 @@ setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, FALSE ); + // Request the concentrate pumps mixing ratios and the DG fill mode prepare time + cmdRequestDGMixingRatios(); + return currentTreatmentParamsState; } Index: firmware/App/Modes/ModeTreatmentParams.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/ModeTreatmentParams.h (.../ModeTreatmentParams.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Modes/ModeTreatmentParams.h (.../ModeTreatmentParams.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -93,8 +93,8 @@ S32 getTreatmentParameterS32( TREATMENT_PARAM_T param ); // Get a specified signed integer treatment parameter F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ); // Get a specified floating point treatment parameter BOOL isTreatmentParamInRange( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ); // Check range for a proposed treatment parameter value -F32 getUltrafiltrationVolumeOriginal( void ); // Get the original ultrafiltration volume, set in pre-treatment mode by user. -F32 getUltrafiltrationRateOriginal( void ); // Get/calculate the original ultrafiltration rate, by ultrafiltration volume and treatment duration set in pre-treatment mode by user. +F32 getUltrafiltrationVolumeOriginal( void ); // Get the original ultrafiltration volume, set in pre-treatment mode by user. +F32 getUltrafiltrationRateOriginal( void ); // Get/calculate the original ultrafiltration rate, by ultrafiltration volume and treatment duration set in pre-treatment mode by user. BOOL testSetTreatmentParameter( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ); // Set a specific treatment parameter value Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -rf1c099b79e0825afe54379577454518f7a134a73 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision f1c099b79e0825afe54379577454518f7a134a73) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -43,12 +43,12 @@ #define PUMP_SELF_TEST_FLOW_RATE_ML_MIN 100 ///< Self-test pump flow rate in mL/min. #define BLOOD_PUMP_RUN_TIME_PRESSURE_SELF_TEST ( 5 * MS_PER_SECOND ) ///< Pressure self-test time to run blood pump in ms. -#define NORMALIZED_PRESSURE_SELF_TEST_TIME ( 2 * MS_PER_SECOND ) ///< Time to wait for pressure to normalize in ms. +#define NORMALIZED_PRESSURE_SELF_TEST_TIME ( 4 * MS_PER_SECOND ) ///< Time to wait for pressure to normalize in ms. #define ARTERIAL_PRESSURE_SELF_TEST_LOW_LIMIT_MMHG -50.0 ///< Arterial pressure low limit after running blood pump. #define VENOUS_PRESSURE_SELF_TEST_HIGH_LIMIT_MMHG 400 ///< Venous pressure high limit after running blood pump. -#define NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG 5.0 ///< Difference in pressure readings after return to normal state tolerance (in mmHg). +#define NORMAL_PRESSURE_DIFF_TOLERANCE_MMHG 10.0 ///< Difference in pressure readings after return to normal state tolerance (in mmHg). #define DIP_FLOW_RATE_SETUP_ML_MIN 150 ///< Dialysate inlet pump flow rate during the setup for wet self-test. #define DIP_FLOW_RATE_FIRST_DISPLACEMENT_ML_MIN 100 ///< Dialysate inlet pump flow rate during the first displacement in wet self-test. @@ -58,7 +58,7 @@ #define WET_SELF_TEST_FIRST_DISPLACEMENT_TARGET_VOLUME_ML 100.0 ///< Target of first displacement volume in ml. #define WET_SELF_TEST_SECOND_DISPLACEMENT_TARGET_VOLUME_ML 600.0 ///< Target of second displacement volume in ml. #define WET_SELF_TEST_INTEGRATED_VOLUME_TOLERANCE 5.0 ///< Tolerance on integrated volume in percentage. -#define WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G 1.5 ///< Tolerance in the load cell readings of the displacement in grams. +#define WET_SELF_TEST_DISPLACEMENT_TOLERANCE_G 25.0 ///< Tolerance in the load cell readings of the displacement in grams (2%). #define WET_SELF_TEST_DISPLACEMENT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Time to displace dialysate in wet self-test in ms. #define RESERVOIR_SETTLE_TIME_MS ( 4 * MS_PER_SECOND ) ///< Time allotted for reservoir to settle in ms. @@ -324,7 +324,7 @@ } else { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_NO_CART_SELF_TEST_TIMEOUT, currentNoCartSelfTestsState ); +// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_NO_CART_SELF_TEST_TIMEOUT, currentNoCartSelfTestsState ); } } } @@ -823,19 +823,18 @@ { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; - BUBBLE_STATUS_T const ADABubbleStatus = getBubbleStatus( ADA ); BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); - if ( ( BUBBLE_DETECTED == ADABubbleStatus ) && ( BUBBLE_DETECTED == ADVBubbleStatus ) && + if ( ( BUBBLE_DETECTED == ADVBubbleStatus ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) { state = DRY_SELF_TESTS_OCCLUSION_SENSORS_STATE; } - else - { - activateAlarmNoData( ALARM_ID_INSTALL_NEW_CARTRIDGE ); - } +// else +// { +// activateAlarmNoData( ALARM_ID_INSTALL_NEW_CARTRIDGE ); +// } if ( TRUE == doesAlarmStatusIndicateStop() ) { @@ -1103,7 +1102,6 @@ if ( setupDisplacementVolume <= 0 ) { signalDialInPumpHardStop(); - selfTestBubble( ADA ); selfTestBubble( ADV ); state = WET_SELF_TESTS_BUBBLES_STATE; } @@ -1129,7 +1127,7 @@ { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BUBBLES_STATE; - if ( ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADA ) ) && ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADV ) ) ) + if ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADV ) ) { state = WET_SELF_TESTS_PRIME_CHECK_STATE; } @@ -1157,14 +1155,15 @@ WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_PRIME_CHECK_STATE; *result = SELF_TEST_STATUS_FAILED; - BUBBLE_STATUS_T const ADABubbleStatus = getBubbleStatus( ADA ); BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); #ifndef SKIP_AIR_BUBBLE_CHECK if ( ( BUBBLE_NOT_DETECTED == ADABubbleStatus ) && ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) ) #endif { +#ifndef IGNORE_BLOOD_LEAK_SELF_TEST zeroBloodLeak(); +#endif state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; *result = SELF_TEST_STATUS_PASSED; } @@ -1190,7 +1189,9 @@ { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; +#ifndef IGNORE_BLOOD_LEAK_SELF_TEST if ( SELF_TEST_STATUS_PASSED == getBloodLeakSelfTestStatus() ) +#endif { settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -r2c9bbece8057254f8389c26a818081002fb69a77 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 2c9bbece8057254f8389c26a818081002fb69a77) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/AlarmMgmtSWFaults.h =================================================================== diff -u -r549119eae64732f124d22df66de4fc88c56193c0 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 549119eae64732f124d22df66de4fc88c56193c0) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/CommBuffers.h =================================================================== diff -u -r9ac7866cce73b5281c34626ab5903409778e2b19 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/CommBuffers.h (.../CommBuffers.h) (revision 9ac7866cce73b5281c34626ab5903409778e2b19) +++ firmware/App/Services/CommBuffers.h (.../CommBuffers.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/FPGA.c =================================================================== diff -u -r71b08e3335b0c111cc57a562089e8ac0b206d258 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 71b08e3335b0c111cc57a562089e8ac0b206d258) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/FPGA.h =================================================================== diff -u -r2c9bbece8057254f8389c26a818081002fb69a77 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision 2c9bbece8057254f8389c26a818081002fb69a77) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/Interrupts.c =================================================================== diff -u -r9ac7866cce73b5281c34626ab5903409778e2b19 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision 9ac7866cce73b5281c34626ab5903409778e2b19) +++ firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/PIControllers.c =================================================================== diff -u -r3d8d8451d10aaf2ea9fc9d83857699ef1ae1a0be -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 3d8d8451d10aaf2ea9fc9d83857699ef1ae1a0be) +++ firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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/PIControllers.h =================================================================== diff -u -r3d8d8451d10aaf2ea9fc9d83857699ef1ae1a0be -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision 3d8d8451d10aaf2ea9fc9d83857699ef1ae1a0be) +++ firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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 -rf1c099b79e0825afe54379577454518f7a134a73 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision f1c099b79e0825afe54379577454518f7a134a73) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -21,13 +21,13 @@ #include "sci.h" #include "sys_dma.h" -#include "SystemComm.h" -#include "Comm.h" -#include "Interrupts.h" -#include "OperationModes.h" +#include "Comm.h" +#include "Interrupts.h" +#include "OperationModes.h" +#include "SystemComm.h" +#include "SystemCommMessages.h" #include "Timers.h" #include "Utilities.h" -#include "SystemCommMessages.h" /** * @addtogroup SystemComm @@ -38,15 +38,8 @@ #define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit #define NUM_OF_CAN_IN_BUFFERS 7 ///< Number of CAN buffers for receiving -#ifndef DEBUG_ENABLED - #define NUM_OF_MSG_IN_BUFFERS 7 ///< Number of Msg buffers for receiving -#else - #define NUM_OF_MSG_IN_BUFFERS 8 - #define SCI1_RECEIVE_DMA_REQUEST 30 - #define SCI1_TRANSMIT_DMA_REQUEST 31 -#endif +#define NUM_OF_MSG_IN_BUFFERS 7 ///< Number of Msg buffers for receiving - #define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< If transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on #define MAX_XMIT_RETRIES 5 ///< Maximum number of retries on no transmit complete interrupt timeout @@ -57,7 +50,7 @@ #define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window #define MSG_NOT_ACKED_TIMEOUT_MS 150 ///< Maximum time for a Denali message that requires ACK to be ACK'd -#define MSG_NOT_ACKED_TIMEOUT_MS_INIT 5000 ///< Maximum time for a Denali message that requires ACK to be ACK'd on the INIT state for the first (UI version request) message of the POST +#define MSG_NOT_ACKED_TIMEOUT_MS_INIT 5000 ///< Maximum time for a Denali message that requires ACK to be ACK'd on the INIT state for the first (UI version request) message of the POST #define MSG_NOT_ACKED_MAX_RETRIES 3 ///< Maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm #define PENDING_ACK_LIST_SIZE 25 ///< Maximum number of Denali messages that can be pending ACK at any given time @@ -99,9 +92,6 @@ COMM_BUFFER_IN_CAN_UI_2_HD, COMM_BUFFER_IN_CAN_UI_BROADCAST, COMM_BUFFER_IN_CAN_PC, -#ifdef DEBUG_ENABLED - COMM_BUFFER_IN_UART_PC -#endif }; static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. @@ -122,16 +112,6 @@ static U32 badCANCount; // Test code in support of EMC testing #endif -#ifdef DEBUG_ENABLED - // Debug buffers - static U08 pcXmitPacket[ 1024 ]; - static U08 pcRecvPacket[ PC_MESSAGE_PACKET_SIZE ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - // DMA control records - static g_dmaCTRL pcDMAXmitControlRecord; - static g_dmaCTRL pcDMARecvControlRecord; -#endif - // ********** private function prototypes ********** static void clearCANXmitBuffers( void ); @@ -151,11 +131,6 @@ static BOOL matchACKtoPendingACKList( S16 seqNo ); static void checkPendingACKList( void ); -#ifdef DEBUG_ENABLED - static void initUARTAndDMA( void ); - static U32 transmitNextUARTPacket( void ); -#endif - /*********************************************************************//** * @brief * The initSystemComm function initializes the SystemComm module. @@ -167,11 +142,6 @@ { U32 i; -#ifdef DEBUG_ENABLED - // Initialize UART and DMA for PC communication - initUARTAndDMA(); -#endif - // Initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); @@ -341,14 +311,6 @@ } } } - -#ifdef DEBUG_ENABLED - // If UART transmitter is idle, start transmitting any pending packets - if ( FALSE == isSCI1DMATransmitInProgress() ) - { - transmitNextUARTPacket(); - } -#endif } /*********************************************************************//** @@ -401,113 +363,8 @@ } } -/*********************************************************************//*** - * @brief - * The handleUARTMsgRecvPacketInterrupt function handles a DMA UART receive - * packet completed interrupt. - * @details Inputs: none - * @details Outputs: UART received packet interrupt handled. - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -void handleUARTMsgRecvPacketInterrupt( void ) -{ - // Buffer received packet - addToCommBuffer( COMM_BUFFER_IN_UART_PC, pcRecvPacket, PC_MESSAGE_PACKET_SIZE ); - // Prepare to receive next packet - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} -#endif - /*********************************************************************//** * @brief - * The handleUARTMsgXmitPacketInterrupt function handles a DMA UART transmit - * packet completed interrupt. - * @details Inputs: none - * @details Outputs: UART transmit packet interrupt handled. - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -void handleUARTMsgXmitPacketInterrupt( void ) -{ - U32 bytesXmitted = transmitNextUARTPacket(); - - if ( 0 == bytesXmitted ) - { - signalSCI1XmitsCompleted(); - } -} -#endif - -/*********************************************************************//** - * @brief - * The initUARTAndDMA function initializes the SCI1 peripheral and the DMA - * to go with it for PC communication. - * @details Inputs: none - * @details Outputs: SCI1 and DMA initialized - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -static void initUARTAndDMA( void ) -{ - // Enable DMA block transfer complete interrupts - dmaEnableInterrupt( DMA_CH1, BTC ); - dmaEnableInterrupt( DMA_CH3, BTC ); - - // Assign DMA channels to h/w DMA requests - dmaReqAssign( DMA_CH1, SCI1_RECEIVE_DMA_REQUEST ); - dmaReqAssign( DMA_CH3, SCI1_TRANSMIT_DMA_REQUEST ); - // Set DMA channel priorities - dmaSetPriority( DMA_CH1, HIGHPRIORITY ); - dmaSetPriority( DMA_CH3, LOWPRIORITY ); - - // Initialize PC DMA Transmit Control Record - pcDMAXmitControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) - pcDMAXmitControlRecord.DADD = (U32)(&(sciREG->TD)); // Dest. is SCI2 xmit register - pcDMAXmitControlRecord.SADD = (U32)pcXmitPacket; // Source - pcDMAXmitControlRecord.CHCTRL = 0; // No chaining - pcDMAXmitControlRecord.ELCNT = 1; // Frame is 1 element - pcDMAXmitControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // Block is 8 frames - pcDMAXmitControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte - pcDMAXmitControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMAXmitControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer - pcDMAXmitControlRecord.ADDMODEWR = ADDR_FIXED; // Dest. addressing mode is fixed - pcDMAXmitControlRecord.ADDMODERD = ADDR_INC1; // Source addressing mode is post-increment - pcDMAXmitControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off - pcDMAXmitControlRecord.ELSOFFSET = 0; // Not used - pcDMAXmitControlRecord.ELDOFFSET = 0; // Not used - pcDMAXmitControlRecord.FRSOFFSET = 0; // Not used - pcDMAXmitControlRecord.FRDOFFSET = 0; // Not used - - // Initialize PC DMA Receipt Control Record - pcDMARecvControlRecord.PORTASGN = 4; // Port B (only choice per datasheet) - pcDMARecvControlRecord.SADD = (U32)(&(sciREG->RD)); // Source is SCI2 recv register - pcDMARecvControlRecord.DADD = (U32)pcRecvPacket; // Transfer destination address - pcDMARecvControlRecord.CHCTRL = 0; // No chaining - pcDMARecvControlRecord.ELCNT = 1; // Frame is 1 element - pcDMARecvControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // Block is 8 frames - pcDMARecvControlRecord.RDSIZE = ACCESS_8_BIT; // Element size is 1 byte - pcDMARecvControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMARecvControlRecord.TTYPE = FRAME_TRANSFER; // Transfer type is block transfer - pcDMARecvControlRecord.ADDMODERD = ADDR_FIXED; // Source addressing mode is fixed - pcDMARecvControlRecord.ADDMODEWR = ADDR_INC1; // Dest. addressing mode is post-increment - pcDMARecvControlRecord.AUTOINIT = AUTOINIT_OFF; // Auto-init off - pcDMARecvControlRecord.ELDOFFSET = 0; // Not used - pcDMARecvControlRecord.ELSOFFSET = 0; // Not used - pcDMARecvControlRecord.FRDOFFSET = 0; // Not used - pcDMARecvControlRecord.FRSOFFSET = 0; // Not used - - // Initiate PC packet receiving readiness via DMA - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} -#endif - -/*********************************************************************//** - * @brief * The isCANBoxForXmit function determines whether a given CAN message box * is configured for transmit. * @details Inputs: CAN_OUT_BUFFERS[] @@ -656,39 +513,7 @@ return result; } -/*********************************************************************//** - * @brief - * The transmitNextUARTPacket function sets up and initiates a DMA transmit - * of the next packet pending transmit (if any) via UART. - * @details Inputs: Output UART Comm Buffer(s) - * @details Outputs: UART DMA transmit initiated. - * @return number of bytes transmitted - *************************************************************************/ -#ifdef DEBUG_ENABLED -static U32 transmitNextUARTPacket( void ) -{ - U32 result = 0; - U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); - if ( dataPend > 0 ) - { - result = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, dataPend ); - - // If there is data to transmit, transmit it - if ( result > 0 ) - { - signalSCI1XmitsInitiated(); - pcDMAXmitControlRecord.FRCNT = result; // Set DMA transfer size - dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); - dmaSetChEnable( DMA_CH3, DMA_HW ); - setSCI1DMATransmitInterrupt(); - } - } - - return result; -} -#endif - /************************************************************************* ********************** RECEIVE SUPPORT FUNCTIONS ************************* *************************************************************************/ @@ -1048,12 +873,13 @@ // Find expired messages pending ACK for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { // Pending ACK expired? + { // Pending ACK expired? U32 timeoutPeriod = MSG_NOT_ACKED_TIMEOUT_MS; // set the timeout as default + if ( MODE_INIT == getCurrentOperationMode() ) { // change it to longer timeout if the HD is in INIT state timeoutPeriod = MSG_NOT_ACKED_TIMEOUT_MS_INIT; - } + } if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, timeoutPeriod ) ) ) { // If retries left, reset and resend pending message if ( pendingAckList[ i ].retries > 0 ) @@ -1311,6 +1137,10 @@ handleStopHDRTCClock( message ); break; + case MSG_ID_DG_CONCENTRATE_MIXING_RATIOS_DATA: + handleDGMixingRatios( message ); + break; + // NOTE: this always must be the last case case MSG_ID_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); @@ -1776,6 +1606,10 @@ handleTestSyringePumpForceSensorCalibrateRequest( message ); break; + case MSG_ID_HD_FAN_RPM_ALARM_START_TIME_OFFSET_OVERRIDE: + handleTestFansRPMAlarmStartTimeOffsetOverrideRequest( message ); + break; + default: // Unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemComm.h =================================================================== diff -u -r9ac7866cce73b5281c34626ab5903409778e2b19 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision 9ac7866cce73b5281c34626ab5903409778e2b19) +++ firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -15,9 +15,9 @@ * ***************************************************************************/ -#include // For memcpy() +#include // For memcpy() -#include "reg_system.h" +#include "reg_system.h" // Used to access system register to reset processor on request #include "Accel.h" #include "AlarmLamp.h" @@ -49,10 +49,6 @@ // ********** private definitions ********** -#ifdef DEBUG_ENABLED - #define DEBUG_EVENT_MAX_TEXT_LEN 40 -#endif - #define MAX_MSGS_BLOCKED_FOR_XMIT 8 ///< Maximum number of messages to block transmission for. #pragma pack(push,1) @@ -1369,15 +1365,17 @@ /*********************************************************************//** * @brief - * The sendDialysateTempTargetsToDG function constructs a dialysate temperature - * set points message for DG and queues the msg for transmit on the appropriate CAN channel. + * The sendDialysateTempTargetsAndReservoirCycleTimeToDG function constructs a + * dialysate temperature set points message and the active reservoir cycle time + * for DG and queues the msg for transmit on the appropriate CAN channel. * @details Inputs: none * @details Outputs: Dialysate temperature set points msg constructed and queued. - * @param primary temperature set point for primary heater - * @param trimmer temperature set point for trimmer heater + * @param trimmer temperature set point for trimmer heater + * @param rsrvrCycleTime active reservoir cycle time in milliseconds + * @param rsrvrWait2Switch time to switch the inactive and active reservoirs in milliseconds * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ -BOOL sendDialysateTempTargetsToDG( F32 primary, F32 trimmer ) +BOOL sendDialysateHeatingParamsToDG( DG_CMD_DIALYSATE_HEATING_PARAMS_T *params ) { BOOL result; MESSAGE_T msg; @@ -1386,11 +1384,9 @@ // Create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS; - msg.hdr.payloadLen = sizeof( F32 ) + sizeof( F32 ); + msg.hdr.payloadLen = sizeof( DG_CMD_DIALYSATE_HEATING_PARAMS_T ); - memcpy( payloadPtr, &primary, sizeof( F32 ) ); - payloadPtr += sizeof( F32 ); - memcpy( payloadPtr, &trimmer, sizeof( F32 ) ); + memcpy( payloadPtr, params, sizeof( DG_CMD_DIALYSATE_HEATING_PARAMS_T ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_DG, ACK_REQUIRED ); @@ -1461,10 +1457,11 @@ * @details Inputs: none * @details Outputs: DG fill command msg constructed and queued. * @param cmd start or stop fill command - * @param fillToVolumeMl volume (in mL) to fill inactive reservoir to + * @param fillToVolumeMl volume (in mL) to fill inactive reservoir to + * @param targetFlowLRatePM target fill flow rate in L/min * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ -BOOL sendDGFillCommand( U32 cmd, U32 fillToVolumeMl ) +BOOL sendDGFillCommand( U32 cmd, U32 fillToVolumeMl, F32 targetFlowRateLPM ) { BOOL result; MESSAGE_T msg; @@ -1473,11 +1470,13 @@ // Create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_DG_FILL_CMD; - msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ); + msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ) + sizeof( F32 ); memcpy( payloadPtr, &fillToVolumeMl, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); - memcpy( payloadPtr, &cmd, sizeof( U32 ) ); + memcpy( payloadPtr, &cmd, sizeof( U32 ) ); + payloadPtr += sizeof( F32 ); + memcpy( payloadPtr, &targetFlowRateLPM, sizeof( F32 ) ); // 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_DG, ACK_REQUIRED ); @@ -1935,6 +1934,52 @@ return result; } +/*********************************************************************//** + * @brief + * The sendDGConcentrateMixingRatiosRequest function constructs a request msg + * to the DG to request the concentrate ratios and queues the msg for transmit + * on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG POST result request msg constructed and queued. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendDGConcentrateMixingRatiosRequest( void ) +{ + BOOL result; + MESSAGE_T msg; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_REQUEST_DG_CONCENTRATE_MIXING_RATIOS; + msg.hdr.payloadLen = 0; + + // 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_DG, ACK_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDGMixingRatios function handles a concentrate mixing ratios and + * prepare fill time broadcast from DG. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleDGMixingRatios( MESSAGE_T *message ) +{ + if ( message->hdr.payloadLen == sizeof( DG_MIXING_RATIOS_T ) ) + { + DG_MIXING_RATIOS_T payload; + + memcpy( &payload, message->payload, sizeof( DG_MIXING_RATIOS_T ) ); + + setDGMixingRatios( payload ); + } +} + #ifdef EMC_TEST_BUILD BOOL broadcastCANErrorCount( U32 count ) { @@ -2262,7 +2307,7 @@ TEMPERATURE_SENSORS_DATA_T payload; memcpy( &payload, message->payload, sizeof( TEMPERATURE_SENSORS_DATA_T ) ); - setDialysateTemperatureReadings( payload.inletDialysate, payload.outletRedundant ); + setDialysateTemperatureReadings( payload.TDi, payload.TRo ); } // TODO - what to do if invalid payload length? // TODO - how to know if DG stops sending these? @@ -2279,11 +2324,11 @@ *************************************************************************/ void handleDialysateFlowData( MESSAGE_T *message ) { - if ( message->hdr.payloadLen == sizeof(DIALYSATE_FLOW_METER_DATA_T) ) + if ( message->hdr.payloadLen == sizeof( DIALYSATE_FLOW_METER_DATA_T ) ) { DIALYSATE_FLOW_METER_DATA_T payload; - memcpy( &payload, message->payload, sizeof(DIALYSATE_FLOW_METER_DATA_T) ); + memcpy( &payload, message->payload, sizeof( DIALYSATE_FLOW_METER_DATA_T ) ); setDialysateFlowData( payload.measuredDialysateFlowRate ); } } @@ -3158,55 +3203,6 @@ *************************************************************************/ -#ifdef DEBUG_ENABLED - /*********************************************************************//** - * @brief - * The sendDebugData function sends debug data out to the PC port. - * @details - * @details Inputs: none - * @details Outputs: PC serial port - * @param dbgData Pointer to debug data - * @param len number of bytes of debug data - * @return TRUE if debug data was successfully queued for transmit, FALSE if not - *************************************************************************/ - BOOL sendDebugData( U08 *dbgData, U32 len ) - { - BOOL result; - - // Add serialized message data to appropriate comm buffer - result = addToCommBuffer( COMM_BUFFER_OUT_UART_PC, dbgData, len ); - - return result; - } - - /*********************************************************************//** - * @brief - * The sendDebugDataToUI function sends debug string to the UI for logging. - * @details Inputs: none - * @details Outputs: Message constructed and queued for transmit - * @param str Pointer to debug string - * @return none - *************************************************************************/ - void sendDebugDataToUI( U08 *str ) - { - MESSAGE_T msg; - U32 txtLen = strlen( (char*)str ); - U08 *payloadPtr = msg.payload; - - // Create a message record - blankMessage( &msg ); - msg.hdr.msgID = MSG_ID_HD_DEBUG_EVENT; - msg.hdr.payloadLen = DEBUG_EVENT_MAX_TEXT_LEN + 1; // Add 1 byte for null terminator - if ( txtLen <= DEBUG_EVENT_MAX_TEXT_LEN ) - { - memcpy( payloadPtr, str, txtLen + 1 ); - - // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer - serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_UI, ACK_NOT_REQUIRED ); - } - } -#endif - /*********************************************************************//** * @brief * The isTestingActivated function determines whether a tester has successfully @@ -5127,6 +5123,7 @@ if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) { memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) { result = testSetBatteryRemainingPercentOverride( payload.state.u32 ); @@ -6730,7 +6727,6 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } - /*********************************************************************//** * @brief * The handleStopHDRTCClock function handles a request to stop the RTC clock. @@ -6752,4 +6748,37 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } +/*********************************************************************//** + * @brief + * The handleTestFansRPMAlarmStartTimeOverrideRequest function handles a + * request to override the fan RPM alarm start time. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestFansRPMAlarmStartTimeOffsetOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) ); + + if ( FALSE == payload.reset ) + { + result = testSetFanRPMAlarmStartTimeOffsetOverride( payload.state.u32, payload.index ); + } + else + { + result = testResetFanRPMAlarmStartTimeOffsetOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r2a6ac80309cb52922f856b3eb4ff2c876b44c0d6 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 2a6ac80309cb52922f856b3eb4ff2c876b44c0d6) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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 -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -159,6 +159,7 @@ { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; +#ifndef DISABLE_WD_AND_SFTY_POST_TESTS switch ( watchdogSelfTestState ) { case WATCHDOG_SELF_TEST_STATE_START: @@ -175,7 +176,7 @@ { F32 v24 = getIntADCVoltageConverted( INT_ADC_24V_ACTUATORS ); F32 audioCurrent = getFPGABackupAlarmAudioCurrent(); - + // Verify 24V is down when w.d. expired if ( v24 > MAX_24V_LEVEL_ON_WATCHDOG_EXPIRED ) { @@ -242,7 +243,11 @@ result = SELF_TEST_STATUS_FAILED; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_WATCHDOG_INVALID_SELF_TEST_STATE, watchdogSelfTestState ) break; - } + } +#else + watchdogSelfTestStatus = SELF_TEST_STATUS_PASSED; + result = watchdogSelfTestStatus; +#endif return result; } Index: firmware/App/Tasks/TaskPriority.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -92,9 +92,10 @@ // Monitor fluid leak detector execFluidLeak(); +#ifndef IGNORE_BLOOD_LEAK_SELF_TEST // Monitor blood leak detector execBloodLeak(); - +#endif // Monitor air bubble detectors execBubbles();