Index: dialin/hd/alarms.py =================================================================== diff -u -r02e6bbf85f0699488317daa135d2530bc5b19507 -r05176be46b1bcb2cd406be63b7888900b3086b67 --- dialin/hd/alarms.py (.../alarms.py) (revision 02e6bbf85f0699488317daa135d2530bc5b19507) +++ dialin/hd/alarms.py (.../alarms.py) (revision 05176be46b1bcb2cd406be63b7888900b3086b67) @@ -17,6 +17,7 @@ DenaliChannels) from ..utils.conversions import integer_to_bytearray from .constants import RESET, NO_RESET +from collections import OrderedDict import struct @@ -63,6 +64,59 @@ START_POS_ALARM_ID = DenaliMessage.PAYLOAD_START_INDEX END_POS_ALARM_ID = START_POS_ALARM_ID + 2 + # See AlarmDefs.h + ALARM_ID_NO_ALARM = 0 + ALARM_ID_SOFTWARE_FAULT = 1 # Requires reboot + ALARM_ID_STUCK_BUTTON_TEST_FAILED = 2 + ALARM_ID_FPGA_POST_TEST_FAILED = 3 + ALARM_ID_WATCHDOG_POST_TEST_FAILED = 4 + ALARM_ID_UI_COMM_POST_FAILED = 5 + ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK = 6 + ALARM_ID_BLOOD_PUMP_MC_SPEED_CHECK = 7 + ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK = 8 + ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK = 9 + ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK = 10 + ALARM_ID_DIAL_IN_PUMP_MC_SPEED_CHECK = 11 + ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK = 12 + ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK = 13 + ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK = 14 + ALARM_ID_DIAL_OUT_PUMP_MC_SPEED_CHECK = 15 + ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK = 16 + ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK = 17 + ALARM_ID_WATCHDOG_EXPIRED = 18 + ALARM_ID_RTC_COMM_ERROR = 19 + ALARM_ID_RTC_CONFIG_ERROR = 20 + ALARM_ID_DG_COMM_TIMEOUT = 21 + ALARM_ID_UI_COMM_TIMEOUT = 22 + ALARM_ID_COMM_TOO_MANY_BAD_CRCS = 23 + ALARM_ID_TREATMENT_STOPPED_BY_USER = 24 + ALARM_ID_BLOOD_SITTING_WARNING = 25 + ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RESUME = 26 + ALARM_ID_BLOOD_SITTING_TOO_LONG_NO_RINSEBACK = 27 + ALARM_ID_CAN_MESSAGE_NOT_ACKED = 28 + ALARM_ID_OCCLUSION_BLOOD_PUMP = 29 + ALARM_ID_OCCLUSION_DIAL_IN_PUMP = 30 + ALARM_ID_OCCLUSION_DIAL_OUT_PUMP = 31 + ALARM_ID_ARTERIAL_PRESSURE_LOW = 32 + ALARM_ID_ARTERIAL_PRESSURE_HIGH = 33 + ALARM_ID_VENOUS_PRESSURE_LOW = 34 + ALARM_ID_VENOUS_PRESSURE_HIGH = 35 + ALARM_ID_UF_RATE_TOO_HIGH_ERROR = 36 + ALARM_ID_UF_VOLUME_ACCURACY_ERROR = 37 + ALARM_ID_RTC_BATTERY_LOW = 38 + ALARM_ID_RTC_OR_TIMER_ACCURACY_FAILURE = 39 + ALARM_ID_RTC_RAM_OPS_ERROR = 40 + ALARM_ID_NVDATA_EEPROM_OPS_FAILURE = 41 + ALARM_ID_NVDATA_MFG_RECORD_CRC_ERROR = 42 + ALARM_ID_NVDATA_SRVC_RECORD_CRC_ERROR = 43 + ALARM_ID_NVDATA_CAL_RECORD_CRC_ERROR = 44 + ALARM_ID_NVDATA_HW_USAGE_DATA_CRC_ERROR = 45 + AlARM_ID_NVDATA_DISINFECTION_DATE_CRC_ERROR = 46 + ALARM_ID_RO_PUMP_OUT_PRESSURE_OUT_OF_RANGE = 47 + ALARM_ID_TEMPERATURE_SENSORS_OUT_OF_RANGE = 48 + ALARM_ID_TEMPERATURE_SENSORS_INCONSISTENT = 49 + ALARM_ID_HD_COMM_TIMEOUT = 50 + def __init__(self, can_interface): """ @param can_interface: Denali Can Messenger object @@ -94,6 +148,13 @@ # alarm states based on received HD alarm activation and alarm clear messages self.alarm_states = [False] * 500 + self.ids = OrderedDict() + for attr in dir(self): + if not callable(getattr(self, attr)) and attr.startswith("ALARM_ID"): + self.ids[attr] = getattr(self, attr) + # self.ids = sorted(self.ids, key=lambda x: x[1]) + self.ids = OrderedDict(sorted(self.ids.items(), key=lambda key: key[1])) + def _handler_alarms_status_sync(self, message): """ Handles published alarms status messages. alarms status data are captured @@ -160,8 +221,6 @@ message_id=self.MSG_ID_HD_ALARM_STATE_OVERRIDE, payload=payload) - print("override alarm state") - # Send message received_message = self.can_interface.send(message) @@ -172,13 +231,9 @@ str_res = "reset back to normal" else: str_res = ("active" if state != 0 else "inactive") - print("Alarm state overridden to " + str_res + ":" + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK - return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] - else: - print("Timeout!!!!") - return False + return 1 == received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + return False def cmd_alarm_time_override(self, time_ms, alarm, reset=NO_RESET): """ Index: tests/test_alarms.py =================================================================== diff -u --- tests/test_alarms.py (revision 0) +++ tests/test_alarms.py (revision 05176be46b1bcb2cd406be63b7888900b3086b67) @@ -0,0 +1,89 @@ +########################################################################### +# +# Copyright (c) 2019-2019 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 test_demo.py +# +# @date 15-May-2020 +# @author P. Lucia +# +# @brief This is a demo script to exercise the HD and DG. +# +############################################################################ +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD +import time + +def test_disable_all_hd_alarms(): + """ + Disables all hd alarms + \returns None + """ + hd = HD() + + if hd.cmd_log_in_to_hd(): + hd.ui.cmd_ui_request_hd_version() + time.sleep(0.5) + print(f"Current HD version: {hd.ui.hd_version}") + for desc, val in hd.alarms.ids.items(): + hd.alarms.cmd_alarm_state_override(0, val) + time.sleep(0.5) + +def test_hd_alarms(): + """ + Simulates all HD alarms + \returns None + """ + hd = HD() + + alarm_faults = [ + 'ALARM_ID_NO_ALARM', + 'ALARM_ID_SOFTWARE_FAULT', + 'ALARM_ID_STUCK_BUTTON_TEST_FAILED', + 'ALARM_ID_FPGA_POST_TEST_FAILED', + 'ALARM_ID_WATCHDOG_POST_TEST_FAILED', + 'ALARM_ID_UI_COMM_POST_FAILED', + 'ALARM_ID_WATCHDOG_EXPIRED', + 'ALARM_ID_RTC_COMM_ERROR', + 'ALARM_ID_DG_COMM_TIMEOUT', + 'ALARM_ID_UI_COMM_TIMEOUT', + 'ALARM_ID_COMM_TOO_MANY_BAD_CRCS', + 'ALARM_ID_CAN_MESSAGE_NOT_ACKED', + 'ALARM_ID_UF_RATE_TOO_HIGH_ERROR', + 'ALARM_ID_UF_VOLUME_ACCURACY_ERROR', + 'ALARM_ID_RTC_OR_TIMER_ACCURACY_FAILURE', + 'ALARM_ID_NVDATA_CAL_RECORD_CRC_ERROR', + 'AlARM_ID_NVDATA_DISINFECTION_DATE_CRC_ERROR', + 'ALARM_ID_NVDATA_MFG_RECORD_CRC_ERROR', + 'ALARM_ID_RO_PUMP_OUT_PRESSURE_OUT_OF_RANGE', + 'ALARM_ID_TEMPERATURE_SENSORS_OUT_OF_RANGE', + 'ALARM_ID_TEMPERATURE_SENSORS_INCONSISTENT', + 'ALARM_ID_VALVE_CONTROL_FAILURE' + ] + + if hd.cmd_log_in_to_hd(): + hd.ui.cmd_ui_request_hd_version() + time.sleep(0.5) + print(f"Current HD version: {hd.ui.hd_version}") + for desc, val in hd.alarms.ids.items(): + if desc in alarm_faults: + print("Skipping {0}".format(desc)) + continue + print("Testing {0} = {1}".format(desc, val)) + success = hd.alarms.cmd_alarm_state_override(1, val) + time.sleep(10) + if not success: + raise ValueError("Failed to activate alarm {0} = {1}".format(desc, val)) + success = hd.alarms.cmd_alarm_state_override(0, val) + if not success: + raise ValueError("Failed to deactivate alarm {0} = {1}".format(desc, val)) + time.sleep(2) + + +if __name__ == '__main__': + # test_disable_all_hd_alarms() + test_hd_alarms()