Index: dialin/common/msg_defs.py =================================================================== diff -u -ra3f3f5ca6fcb24a47bb3056878bb8ff9e3642fd2 -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- dialin/common/msg_defs.py (.../msg_defs.py) (revision a3f3f5ca6fcb24a47bb3056878bb8ff9e3642fd2) +++ dialin/common/msg_defs.py (.../msg_defs.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -82,7 +82,7 @@ MSG_ID_UI_TREATMENT_END_REQUEST = 0x3C # UI user treatment end request MSG_ID_HD_TREATMENT_END_RESPONSE = 0x3D # HD response to user request to end treatment MSG_ID_HD_AIR_TRAP_DATA = 0x003E # HD broadcast of air trap data - MSG_ID_UI_ALARM_USER_ACKNOWLEDGE = 0x3F # UI user has acknowledged alarm + MSG_ID_ALARM_CONDITION_CLEARED = 0x3F # Broadcast that the alarm condition has been cleared MSG_ID_UI_ALARM_USER_ACTION = 0x40 # UI user has requested an alarm action MSG_ID_USER_UF_PAUSE_RESUME_RESPONSE = 0x41 # HD response to user request to pause or resume UF MSG_ID_DG_CONCENTRATE_PUMP_DATA = 0x42 # DG broadcast of concentrate pump data Index: dialin/ui/__init__.py =================================================================== diff -u -r5f420f989a3b1652faef66c99777233f152954a1 -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- dialin/ui/__init__.py (.../__init__.py) (revision 5f420f989a3b1652faef66c99777233f152954a1) +++ dialin/ui/__init__.py (.../__init__.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -1,2 +1,2 @@ from .hd_simulator import HDSimulator, TXStates, EResponse, TreatmentParameterRejections -from .hd_simulator_alarms import HDProxyAlarms +from .hd_simulator_alarms import HDAlarmsSimulator Index: dialin/ui/hd_simulator.py =================================================================== diff -u -ra3f3f5ca6fcb24a47bb3056878bb8ff9e3642fd2 -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision a3f3f5ca6fcb24a47bb3056878bb8ff9e3642fd2) +++ dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -21,7 +21,7 @@ import subprocess from . import utils, messageBuilder -from .hd_simulator_alarms import HDProxyAlarms +from .hd_simulator_alarms import HDAlarmsSimulator from ..common.msg_defs import RequestRejectReasons, MsgIds from ..common.hd_defs import HDDefs from ..protocols.CAN import (DenaliMessage, @@ -188,7 +188,7 @@ self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_UI_TREATMENT_END_REQUEST.value, self._handler_ui_end_treatment) - self.alarms_simulator = HDProxyAlarms(self.can_interface, self.logger) + self.alarms_simulator = HDAlarmsSimulator(self.can_interface, self.logger) self.treatment_parameter_rejections = TreatmentParameterRejections() Index: dialin/ui/hd_simulator_alarms.py =================================================================== diff -u -rca129a0f29a49ee531f957a8559fea8051364b90 -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision ca129a0f29a49ee531f957a8559fea8051364b90) +++ dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -13,21 +13,24 @@ # @date (original) 28-Sep-2020 # ############################################################################ +import struct +from time import sleep, time from ..protocols.CAN import (DenaliMessage, DenaliCanMessenger, DenaliChannels) from logging import Logger from ..utils.base import _AbstractSubSystem -from ..utils.conversions import integer_to_bytearray -from ..common.msg_defs import MsgIds +from ..utils.conversions import integer_to_bytearray, integer_to_bit_array +from ..common.msg_defs import MsgIds, MsgFieldPositions from ..common.alarm_defs import AlarmList -from time import sleep, time HIGH = 3 MED = 2 LOW = 1 NONE = 0 +HIGH_PRIORITY_COLOR = "#c53b33" +MED_LOW_PRIORITY_COLOR = "#f5a623" class Alarms: @@ -95,7 +98,7 @@ ALARM_ID_DOES_NOT_EXIST = (HIGH, 99, 0, 0, 0) -class HDProxyAlarms(_AbstractSubSystem): +class HDAlarmsSimulator(_AbstractSubSystem): def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object @@ -104,15 +107,16 @@ self.can_interface = can_interface self.logger = logger self.flags = 0 + self.clear_after_user_action = False if self.can_interface is not None: channel_id = DenaliChannels.ui_to_hd_ch_id self.can_interface.register_receiving_publication_function(channel_id, - MsgIds.MSG_ID_UI_ALARM_USER_ACKNOWLEDGE.value, - self._handler_alarm_acknowledge) - self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_USER_REQUEST_ALARM_SILENCE.value, self._handler_alarm_silence) + self.can_interface.register_receiving_publication_function(channel_id, + MsgIds.MSG_ID_UI_ALARM_USER_ACTION.value, + self._handler_user_action) def cmd_activate_alarm_id(self, state: int = HIGH, alarm: int = 0, @@ -326,7 +330,6 @@ else: self.flags = self.cmd_make_alarm_flags(alarms_silenced=0) - def set_flags(self, flags): """ Sets the alarm flags @@ -338,6 +341,7 @@ def _handler_alarm_acknowledge(self, message): """ + TODO: Remove Handles the alarm acknowledge message @param message: the message of user acknowledge, contains the alarmID @@ -355,5 +359,58 @@ @return: None """ - self.logger.debug("Alarm Silence") - self.flags = self.flags | 2 ** 9 + request = message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1][0] + if request: + self.logger.debug("Alarm Silence Request Start {0}".format(request)) + self.flags = self.flags | 2 ** 9 + else: + self.logger.debug("Alarm Silence Request Cancel {0}".format(request)) + self.flags = self.flags & ~2 ** 9 + + self.cmd_send_acknowledge(message) + + def cmd_alarm_condition_cleared(self, alarm_id: int): + """ + Sends the alarm condition cleared message + @param alarm_id: (int) The alarm ID + @return: None + """ + payload = integer_to_bytearray(alarm_id) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_alarm_broadcast_ch_id, + message_id=MsgIds.MSG_ID_ALARM_CONDITION_CLEARED.value, + payload=payload) + + self.can_interface.send(message, 0) + + def _handler_user_action(self, message): + """ + Called when the user responds to an alarm + @return: None + """ + response = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + + self.logger.debug("User response to alarm: {0}".format(response)) + self.cmd_send_acknowledge(message) + if self.clear_after_user_action: + self.cmd_send_clear_alarms() + + def cmd_send_acknowledge(self, message: dict): + """ + Sends a generic acknowledge + + @param message: (dict) The message that was sent we need to ACK + @return: None + """ + seq = struct.unpack('h', bytearray( + message['message'][DenaliMessage.MSG_SEQ_INDEX:DenaliMessage.MSG_ID_INDEX]))[0] + + # send back empty payload since this is an ACK + payload = bytearray() + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_to_ui_ch_id, + message_id=MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, + payload=payload, + seq=-seq) + self.can_interface.send(message, 0) Index: dialin/utils/conversions.py =================================================================== diff -u -r91dc90bd009bdbf5621dcaa1bc12ab3d691673f7 -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- dialin/utils/conversions.py (.../conversions.py) (revision 91dc90bd009bdbf5621dcaa1bc12ab3d691673f7) +++ dialin/utils/conversions.py (.../conversions.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -34,3 +34,14 @@ @return:: byte array """ return struct.pack('> bit) & 1 for bit in range(num_bits - 1, -1, -1)] \ No newline at end of file Index: tests/test_single_alarm.py =================================================================== diff -u --- tests/test_single_alarm.py (revision 0) +++ tests/test_single_alarm.py (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -0,0 +1,45 @@ +########################################################################### +# +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +# WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# @file test_single_alarm.py +# +# @author (last) Peter Lucia +# @date (last) 28-Dec-2020 +# @author (original) Peter Lucia +# @date (original) 28-Dec-2020 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.ui.hd_simulator import HDSimulator +from dialin.ui.hd_simulator_alarms import Alarms +from time import sleep + +hd_simulator = HDSimulator(log_level="DEBUG") +flags = hd_simulator.alarms_simulator.cmd_make_alarm_flags( + no_clear=1, + no_resume=1, + no_rinseback=1, + no_end_treatment=1, + no_new_treatment=1, + user_must_ack=1) +alarm = Alarms.ALARM_ID_ARTERIAL_PRESSURE_HIGH +state = alarm[0] +alarm_id = alarm[1] +escalates_in = alarm[2] +silence_expires = 10 +hd_simulator.alarms_simulator.flags = flags + +# simulate HD broadcasting an alarm every second +for silence_expires in range(10, -1, -1): + + hd_simulator.alarms_simulator.cmd_activate_alarm_id(state, + alarm_id, + escalates_in, + silence_expires, + hd_simulator.alarms_simulator.flags) + sleep(1) Index: tests/unit_tests/test_imports.py =================================================================== diff -u -ra37f46be740bbbbecbdbde1230d5f20d8854fb8e -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 --- tests/unit_tests/test_imports.py (.../test_imports.py) (revision a37f46be740bbbbecbdbde1230d5f20d8854fb8e) +++ tests/unit_tests/test_imports.py (.../test_imports.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) @@ -94,7 +94,7 @@ from dialin.dg import TemperatureSensors from dialin.dg import DGValves - from dialin.ui import HDSimulator, HDProxyAlarms + from dialin.ui import HDSimulator, HDAlarmsSimulator if __name__ == '__main__': sys.exit(unittest.main(verbosity=2).result.wasSuccessful())