Index: dialin/common/msg_ids.py =================================================================== diff -u -rf7927c4086e16a080e6ba1552e10f6d776c84e17 -rc19568936f7925714a39b7951eae672ab91769a4 --- dialin/common/msg_ids.py (.../msg_ids.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -177,6 +177,9 @@ MSG_ID_HD_SET_STANDBY_DISINFECT_SUB_MODE_REQUEST = 0X9A MSG_ID_HD_SET_STANDBY_DISINFECT_SUB_MODE_RESPONSE = 0X9B MSG_ID_HD_DISINFECTS_UI_STATE_READINGS = 0X9C + MSG_ID_REQUEST_HD_USAGE_INFO = 0XA0 + MSG_ID_DG_SWITCHES_DATA = 0xA1 + MSG_ID_HD_SWITCHES_DATA = 0xA2 MSG_ID_CAN_ERROR_COUNT = 0X999 MSG_ID_TESTER_LOGIN_REQUEST = 0X8000 MSG_ID_DIAL_OUT_FLOW_SET_PT_OVERRIDE = 0X8001 @@ -273,6 +276,9 @@ MSG_ID_HD_BUBBLES_DATA_SEND_INTERVAL_OVERRIDE = 0X805D MSG_ID_HD_BUBBLE_STATUS_OVERRIDE = 0X805E MSG_ID_HD_BUBBLE_SELF_TEST_REQUEST = 0X8060 + MSG_ID_HD_BLOOD_PRIME_SAFETY_VOLUME_OVERRIDE = 0X8061 + MSG_ID_HD_SWITCHES_STATUS_OVERRIDE = 0X8062 + MSG_ID_HD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE = 0X8063 MSG_ID_DG_TESTER_LOGIN_REQUEST = 0XA000 MSG_ID_DG_ALARM_STATE_OVERRIDE = 0XA001 MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE = 0XA002 @@ -300,8 +306,8 @@ MSG_ID_DG_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE = 0XA01A MSG_ID_DG_MONITORED_VOLTAGES_OVERRIDE = 0XA01B MSG_ID_DRAIN_PUMP_SET_DELTA_PRESSURE_OVERRIDE = 0XA01C - MSG_ID___AVAILABLE_12 = 0XA01D - MSG_ID___AVAILABLE_13 = 0XA01E + MSG_ID_DG_SWITCHES_STATUS_OVERRIDE = 0XA01D + MSG_ID_DG_SWITCHES_PUBLISH_INTERVAL_OVERRIDE = 0XA01E MSG_ID___AVAILABLE_14 = 0XA01F MSG_ID___AVAILABLE_15 = 0XA020 MSG_ID___AVAILABLE_16 = 0XA021 Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rf7927c4086e16a080e6ba1552e10f6d776c84e17 -rc19568936f7925714a39b7951eae672ab91769a4 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -44,6 +44,7 @@ from .chemical_disinfect import ChemicalDisinfect from .heat_disinfect import HeatDisinfect from .rtc import DGRTC +from .switches import DGSwitches from enum import unique @@ -177,6 +178,7 @@ self.flush = FlushMode(self.can_interface, self.logger) self.chemical_disinfect = ChemicalDisinfect(self.can_interface, self.logger) self.rtc = DGRTC(self.can_interface, self.logger) + self.switches = DGSwitches(self.can_interface, self.logger) def get_version(self): """ Index: dialin/dg/drain_pump.py =================================================================== diff -u -r6e20f4690ce887c351d8c65546f93311e5df6ad1 -rc19568936f7925714a39b7951eae672ab91769a4 --- dialin/dg/drain_pump.py (.../drain_pump.py) (revision 6e20f4690ce887c351d8c65546f93311e5df6ad1) +++ dialin/dg/drain_pump.py (.../drain_pump.py) (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -148,7 +148,7 @@ def cmd_drain_pump_data_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: """ - Constructs and sends the drain pump speed set point override command. + Constructs and sends the drain pump data publication override command. Constraints: Must be logged into DG. Given interval must be non-zero and a multiple of the DG general task interval (50 ms). Index: dialin/dg/switches.py =================================================================== diff -u --- dialin/dg/switches.py (revision 0) +++ dialin/dg/switches.py (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -0,0 +1,157 @@ + +import struct +from ..utils.conversions import integer_to_bytearray +from ..common.msg_defs import MsgIds, MsgFieldPositions +from .constants import RESET, NO_RESET +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from logging import Logger +from enum import unique + + +@unique +class DGSwitchStatus(DialinEnum): + OFF = 0 + ON = 1 + + +@unique +class DGSwitchesName(DialinEnum): + CONCENTRATE_CAP = 0 + DIALYSATE_CAP = 1 + FLUID_DOOR = 2 + + +class DGSwitches(_AbstractSubSystem): + """ + Dialysate Generator (DG) Dialin API sub-class for switches related commands. + """ + + def __init__(self, can_interface, logger: Logger): + """ + DGSwitches constructor + + """ + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_DG_SWITCHES_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_switches_sync) + + self.dg_switches_status = {DGSwitchesName.CONCENTRATE_CAP.name: DGSwitchStatus.OFF.value, + DGSwitchesName.DIALYSATE_CAP.name: DGSwitchStatus.OFF.value, + DGSwitchesName.FLUID_DOOR.name: DGSwitchStatus.OFF.value} + + def get_switches_status(self) -> dict: + """ + Gets the status of a switch + + @return: The status of all of the switches in a dictionary + """ + return self.dg_switches_status + + @_publish(["dg_switches_status"]) + def _handler_switches_sync(self, message): + """ + Handles published drain pump data messages. Switches data are captured + for reference. + + @param message: published drain pump data message + @return: none + """ + conc_cap = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + dialysate_cap = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + fluid_door = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + + self.dg_switches_status[DGSwitchesName.CONCENTRATE_CAP.name] = conc_cap + self.dg_switches_status[DGSwitchesName.DIALYSATE_CAP.name] = dialysate_cap + self.dg_switches_status[DGSwitchesName.FLUID_DOOR] = fluid_door + + def cmd_dg_switch_status_override(self, switch: int, status: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the dg switch status override command + Constraints: + Must be logged into DG. + + @param switch: (int) switch ID that is status is overridden + @param status: (int) status that the switch will be overridden to + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + reset_value = integer_to_bytearray(reset) + sw = integer_to_bytearray(switch) + st = integer_to_bytearray(status) + payload = reset_value + st + sw + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_SWITCHES_STATUS_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override switch status") + + # Send message + received_message = self.can_interface.send(message) + + # If there is no content... + if received_message is not None: + + self.logger.debug("Switch " + str(DGSwitchesName(switch).name) + " to: " + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + + def cmd_dg_switches_data_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the DG switch data publication override command. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG general task interval (50 ms). + + @param ms: (int) interval (in ms) to override with + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_SWITCHES_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override DG switches data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # self.logger.debug(received_message) + if reset == RESET: + str_res = "reset back to normal" + else: + str_res = str(mis) + self.logger.debug( + "DG Switches data broadcast interval overridden to " + str_res + " ms: " + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -rd4cf7e98bfe73fde95043613fa894b64b57d11a8 -rc19568936f7925714a39b7951eae672ab91769a4 --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision d4cf7e98bfe73fde95043613fa894b64b57d11a8) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -36,6 +36,7 @@ from .pressure_occlusion import HDPressureOcclusion from .pretreatment import HDPreTreatment from .syringe_pump import HDSyringePump +from .switches import HDSwitches from ..protocols.CAN import (DenaliMessage, DenaliCanMessenger, DenaliChannels) @@ -116,6 +117,7 @@ self.calibration_record = HDCalibrationNVRecord(self.can_interface, self.logger) self.system_record = HDSystemNVRecords(self.can_interface, self.logger) self.service_record = HDServiceNVRecords(self.can_interface, self.logger) + self.switches = HDSwitches(self.can_interface, self.logger) def get_operation_mode(self): """ Index: dialin/hd/switches.py =================================================================== diff -u --- dialin/hd/switches.py (revision 0) +++ dialin/hd/switches.py (revision c19568936f7925714a39b7951eae672ab91769a4) @@ -0,0 +1,147 @@ + +import struct +from ..utils.conversions import integer_to_bytearray +from ..common.msg_defs import MsgIds, MsgFieldPositions +from .constants import RESET, NO_RESET +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from logging import Logger +from enum import unique + + +@unique +class HDSwitchStatus(DialinEnum): + OFF = 0 + ON = 1 + + +@unique +class HDSwitchesNames(DialinEnum): + FRONT_DOOR = 0 + + +class HDSwitches(_AbstractSubSystem): + """ + @brief Hemodialysis Device (HD) Dialin API sub-class for HD switches related commands. + """ + + def __init__(self, can_interface, logger: Logger): + """ + HDSwitches constructor + + """ + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + channel_id = DenaliChannels.hd_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_HD_SWITCHES_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_switches_sync) + + self.hd_switches_status = {HDSwitchesNames.FRONT_DOOR.name: HDSwitchStatus.OFF.value} + + def get_switches_status(self) -> dict: + """ + Gets the status of a switch + + @return: The status of all of the switches in a dictionary + """ + return self.hd_switches_status + + @_publish(["hd_switches_status"]) + def _handler_switches_sync(self, message): + """ + Handles published drain pump data messages. Switches data are captured + for reference. + + @param message: published drain pump data message + @return: none + """ + front_door = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + + self.hd_switches_status[HDSwitchesNames.FRONT_DOOR.name] = front_door + + def cmd_hd_switch_status_override(self, switch: int, status: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the HD switch status override command + Constraints: + Must be logged into HD. + + @param switch: (int) switch ID that is status is overridden + @param status: (int) status that the switch will be overridden to + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + reset_value = integer_to_bytearray(reset) + sw = integer_to_bytearray(switch) + st = integer_to_bytearray(status) + payload = reset_value + st + sw + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SWITCHES_STATUS_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override switch status") + + # Send message + received_message = self.can_interface.send(message) + + # If there is no content... + if received_message is not None: + + self.logger.debug("Switch " + str(HDSwitchesNames(switch).name) + " to: " + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + + def cmd_hd_switches_data_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the HD switch data publication override command. + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: (int) interval (in ms) to override with + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override HD switches data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # self.logger.debug(received_message) + if reset == RESET: + str_res = "reset back to normal" + else: + str_res = str(mis) + self.logger.debug( + "HD Switches data broadcast interval overridden to " + str_res + " ms: " + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False