Index: firmware/App/Controllers/DialysateFlow.c =================================================================== diff -u --- firmware/App/Controllers/DialysateFlow.c (revision 0) +++ firmware/App/Controllers/DialysateFlow.c (revision 41f49a0643c7cfa35c9c99fb9ac4e6410c968dc5) @@ -0,0 +1,270 @@ +/************************************************************************** +* +* Copyright (c) 2021 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file DialysateFlow.c +* +* @author (last) H. Nguyen +* @date (last) 19-Oct-2021 +* +* @author (original) H. Nguyen +* @date (original) 19-Oct-2021 +* +***************************************************************************/ + +#include +#include "FPGA.h" +#include "NVDataMgmt.h" +#include "PersistentAlarm.h" +#include "DialysateFlow.h" +//#include "SafetyShutdown.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TaskPriority.h" +//#include "Timers.h" + + +/** + * @addtogroup DialysateFlow + * @{ + */ + +// ********** private definitions ********** + +#define DIALYSATE_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the Dialysate flow data is published on the CAN bus. + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). + +#define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. + +#define DIALYSATE_FLOW_ADC_TO_LPM_FACTOR 5555 ///< Conversion factor from pulse period (2us units) to flow rate (L/min) for dialysate flow rate (divide this by pulse period). +#define FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ( 12 * MS_PER_SECOND ) ///< Flow out of range time out in counts. + + +// ********** private data ********** + +static U32 dialysateFlowDataPublicationTimerCounter = 0; ///< Used to schedule Dialysate flow data publication to CAN bus. + +static OVERRIDE_U32_T dialysateFlowDataPublishInterval = { DIALYSATE_FLOW_DATA_PUB_INTERVAL, + DIALYSATE_FLOW_DATA_PUB_INTERVAL, + 0, 0 }; ///< Interval (in ms) at which to publish Dialysate flow data to CAN bus. + +static OVERRIDE_F32_T measuredDialysateFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured Dialysate flow rate (in L/min). + +static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. +static U32 flowFilterCounter = 0; ///< Flow filtering counter. +//static DG_FLOW_SENSORS_CAL_RECORD_T flowSensorsCalRecord; ///< Flow sensors calibration record. + +// ********** private function prototypes ********** + +static void publishDialysateFlowData( void ); +static BOOL processCalibrationData( void ); + +/*********************************************************************//** + * @brief + * The initDialysateFlowMeter function initializes the Dialysate flow module. + * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, + * dialysateFlowDataPublicationTimerCounter + * @details Outputs: none + * @return none + *************************************************************************/ +void initDialysateFlowMeter( void ) +{ + // Initialize the persistent alarm for flow out of upper and lower range + initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + + // Initialize the variables + measuredFlowReadingsSum = 0; + flowFilterCounter = 0; + dialysateFlowDataPublicationTimerCounter = 0; + +} + +/*********************************************************************//** + * @brief + * The execDialysateFlowMeterMonitor function executes the Dialysate flow monitor. + * The Dialysate flow sensor is read, filtered, converted to L/min and calibrated (TODO). + * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredDialysateFlowRateLPM + * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredDialysateFlowRateLPM + * @return none + *************************************************************************/ +void execDialysateFlowMeterMonitor( void ) +{ + U16 dialysateFlowReading = getFPGADialysateMeterFlowRate(); + + // Update sum for flow average calculation + measuredFlowReadingsSum += (S32)dialysateFlowReading; + + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + + // Read flow at the control set + if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) + { + //U32 sensor; + F32 flow = DIALYSATE_FLOW_ADC_TO_LPM_FACTOR / ( (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER ); // Convert flow sensor period to L/min + + // Apply calibration to flow sensor reading +/* measuredROFlowRateLPM.data = pow(flow, 4) * flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].fourthOrderCoeff + + pow(flow, 3) * flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].thirdOrderCoeff + + pow(flow, 2) * flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].secondOrderCoeff + + flow * flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].gain + + flowSensorsCalRecord.flowSensors[ CAL_DATA_RO_PUMP_FLOW_SENSOR ].offset; */ + + // Calibration of the dialysate flow sensor will be implemented later + measuredDialysateFlowRateLPM.data = flow; + + // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that the flow is 0. + if ( FLOW_SENSOR_ZERO_READING == dialysateFlowReading ) + { + measuredDialysateFlowRateLPM.data = 0.0; + } + + measuredFlowReadingsSum = 0; + flowFilterCounter = 0; + } + + // Publish dialysate flow meter data on the CAN bus according to the specified interval + publishDialysateFlowData(); +} + +/*********************************************************************//** + * @brief + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: flowSensorsCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static BOOL processCalibrationData( void ) +{ + BOOL status = TRUE; + U32 sensor; + + // Get the calibration record from NVDataMgmt + DG_FLOW_SENSORS_CAL_RECORD_T calData = getDGFlowSensorsCalibrationRecord(); + + for ( sensor = 0; sensor < NUM_OF_CAL_DATA_FLOW_SENSORS; sensor++ ) + { +#ifndef SKIP_CAL_CHECK + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the flow sensors data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.flowSensors[ sensor ].calibrationTime ) + { + + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_FLOW_SENSORS_INVALID_CAL_RECORD, (U32)sensor ); + status = FALSE; + } +#endif + + // The calibration data was valid, update the local copy +/* flowSensorsCalRecord.flowSensors[ sensor ].fourthOrderCoeff = calData.flowSensors[ sensor ].fourthOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].thirdOrderCoeff = calData.flowSensors[ sensor ].thirdOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].secondOrderCoeff = calData.flowSensors[ sensor ].secondOrderCoeff; + flowSensorsCalRecord.flowSensors[ sensor ].gain = calData.flowSensors[ sensor ].gain; + flowSensorsCalRecord.flowSensors[ sensor ].offset = calData.flowSensors[ sensor ].offset; */ + } + + return status; +} + +/*********************************************************************//** + * @brief + * The publishDialysateFlowData function publishes Dialysate flow data at the set interval. + * @details Inputs: dialysateFlowDataPublicationTimerCounter + * @details Outputs: dialysateFlowDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishDialysateFlowData( void ) +{ + // publish dialysate flow meter data on interval + if ( ++dialysateFlowDataPublicationTimerCounter >= getU32OverrideValue( &dialysateFlowDataPublishInterval ) ) + { + DIALYSATE_FLOW_METER_DATA_T dialysateFlowData; + dialysateFlowData.measuredDialysateFlowRate = getMeasuredDialysateFlowRate(); + + broadcastDialysateFlowData( &dialysateFlowData ); + + dialysateFlowDataPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The getMeasuredDialysateFlowRate function gets the measured Dialysate flow rate. + * @details Inputs: measuredDialysateFlowRateLPM + * @details Outputs: measuredDialysateFlowRateLPM + * @return the current Dialysate flow rate (in L/min). + *************************************************************************/ +F32 getMeasuredDialysateFlowRate( void ) +{ + return getF32OverrideValue( &measuredDialysateFlowRateLPM ); +} + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetDialysateMeterDataPublishIntervalOverride function overrides the + * Dialysate flow data publish interval. + * @details Inputs: dialysateFlowDataPublishInterval + * @details Outputs: dialysateFlowDataPublishInterval + * @param: value : override Dialysate flow data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetDialysateMeterDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_PRIORITY_INTERVAL; + dialysateFlowDataPublishInterval.ovData = intvl; + dialysateFlowDataPublishInterval.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredDialysateFlowRateOverride function overrides the measured + * Dialysate flow rate. + * @details Inputs: measuredDialysateFlowRateLPM + * @details Outputs: measuredDialysateFlowRateLPM + * @param: value : override measured Dialysate flow motor speed (in L/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredDialysateFlowRateOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + measuredDialysateFlowRateLPM.ovInitData = measuredDialysateFlowRateLPM.data; + measuredDialysateFlowRateLPM.ovData = value; + measuredDialysateFlowRateLPM.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/**@}*/ Index: firmware/App/Controllers/DialysateFlow.h =================================================================== diff -u --- firmware/App/Controllers/DialysateFlow.h (revision 0) +++ firmware/App/Controllers/DialysateFlow.h (revision 41f49a0643c7cfa35c9c99fb9ac4e6410c968dc5) @@ -0,0 +1,53 @@ +/************************************************************************** +* +* Copyright (c) 2021 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file DialysateFlow.h +* +* @author (last) H. Nguyen +* @date (last) 19-Oct-2021 +* +* @author (original) H. Nguyen +* @date (original) 19-Oct-2021 +* +***************************************************************************/ + +#ifndef __DIALYSATE_FLOW_H__ +#define __DIALYSATE_FLOW_H__ + +#include "DGCommon.h" + +/** + * @defgroup Dialysate Flow Meter + * @brief Dialysate flow rate monitor module. Monitors the dialysate flow meter. + * The dialysate flow meter is manufactured by ?, PN: ? + * + * @addtogroup Dialysate Flow Meter + * @{ + */ + +// ********** public definitions ********** +#define MAX_DIALYSATE_FLOWRATE_LPM 1.4 ///< Maximum target Dialysate flow rate in L/min. +#define MIN_DIALYSATE_FLOWRATE_LPM 0.2 ///< Minimum target Dialysate flow rate in L/min. + +/// Dialysate flow meter data struct. +typedef struct +{ + F32 measuredDialysateFlowRate; ///< Dialysate flow meter rate average measurement. +} DIALYSATE_FLOW_METER_DATA_T; + +// ********** public function prototypes ********** + +void execDialysateFlowMeterMonitor( void ); +F32 getMeasuredDialysateFlowRate( void ); +void initDialysateFlowMeter( void ); +//BOOL isDialysateFlowMeterRunning( void ); +BOOL testSetDialysateMeterDataPublishIntervalOverride( U32 value ); +BOOL testSetTargetDialysateMeterFlow( F32 flow ); + +/**@}*/ + +#endif