Index: dialin/common/msg_ids.py =================================================================== diff -u -r6e20f4690ce887c351d8c65546f93311e5df6ad1 -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 6e20f4690ce887c351d8c65546f93311e5df6ad1) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -265,6 +265,7 @@ MSG_ID_HD_ALARM_AUDIO_CURRENT_LG_OVERRIDE = 0X8055 MSG_ID_HD_ALARM_BACKUP_AUDIO_CURRENT_OVERRIDE = 0X8056 MSG_ID_HD_VALVES_CURRENT_OVERRIDE = 0X8057 + MSD_ID_HD_VALVES_POSITION_COUNT_OVERRIDE = 0x8058 MSG_ID_HD_SYRINGE_PUMP_STATUS_OVERRIDE = 0X8059 MSG_ID_HD_SYRINGE_PUMP_ENCODER_STATUS_OVERRIDE = 0X805A MSG_ID_HD_SYRINGE_PUMP_ADC_DAC_STATUS_OVERRIDE = 0X805B Index: dialin/dg/calibration_record.py =================================================================== diff -u -r8a13a85045edfcf69bf0e728d294f04b924d732c -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/dg/calibration_record.py (.../calibration_record.py) (revision 8a13a85045edfcf69bf0e728d294f04b924d732c) +++ dialin/dg/calibration_record.py (.../calibration_record.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -121,12 +121,16 @@ if self.current_message <= self.total_messages: self._raw_cal_record += (message['message'][self._RECORD_START_INDEX + self._RECORD_SPECS_BYTES:end_of_data_index]) + if self.current_message == self.total_messages: # Done with getting all the calibration data. self._is_getting_cal_in_progress = False # If all the messages have been received, call another function to process the raw data self._utilities.process_received_record_from_fw(self.dg_calibration_record, self._raw_cal_record) self._handler_received_complete_dg_calibration_record() + # TODO remove + print(self.dg_calibration_record) + # TODO remove @_publish(["dg_calibration_record"]) def _handler_received_complete_dg_calibration_record(self): Index: dialin/dg/conductivity_sensors.py =================================================================== diff -u -r8cc6f4843c77fc7bfe358c9f752740919c25f65f -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/dg/conductivity_sensors.py (.../conductivity_sensors.py) (revision 8cc6f4843c77fc7bfe358c9f752740919c25f65f) +++ dialin/dg/conductivity_sensors.py (.../conductivity_sensors.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -16,6 +16,7 @@ import struct from .constants import RESET,NO_RESET from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from ..utils.checks import check_broadcast_interval_override_ms from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish, DialinEnum from ..common.msg_defs import MsgIds, MsgFieldPositions @@ -137,15 +138,21 @@ self.logger.error("Timeout!!!!") return False - def cmd_conductivity_sensor_data_broadcast_interval_override(self, ms, reset=NO_RESET): + def cmd_conductivity_sensor_data_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: """ Constructs and sends the conductivity sensor data broadcast interval 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: integer - interval (in ms) to override with @param reset: integer - 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 + reset_byte_array = integer_to_bytearray(reset) ms_byte_array = integer_to_bytearray(ms) payload = reset_byte_array + ms_byte_array Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rf9ade5206d6da9dc2ef510ef0d985ecc4bf44924 -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision f9ade5206d6da9dc2ef510ef0d985ecc4bf44924) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -13,7 +13,6 @@ # @date (original) 02-Apr-2020 # ############################################################################ -import struct from .accelerometer import DGAccelerometer from .alarms import DGAlarms from .concentrate_pumps import ConcentratePumps @@ -29,23 +28,22 @@ from .ro_pump import DGROPump from .samplewater import DGSampleWater from .temperature_sensors import TemperatureSensors -from .conductivity_sensors import ConductivitySensors -from .heat_disinfect import HeatDisinfect from .thermistors import Thermistors from .uv_reactors import UVReactors -from .concentrate_pumps import ConcentratePumps from .calibration_record import DGCalibrationNVRecord from .system_record import DGSystemNVRecord from .service_record import DGServiceNVRecord from .scheduled_runs_record import DGScheduledRunsNVRecord from .valves import DGValves - +from .voltages import DGVoltages from ..utils import * -from ..utils.base import _AbstractSubSystem, _publish, _LogManager from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish, _LogManager, DialinEnum from ..common.msg_defs import MsgIds, MsgFieldPositions from .flush import FlushMode from .chemical_disinfect import ChemicalDisinfect +from .heat_disinfect import HeatDisinfect +from .rtc import DGRTC from enum import unique @@ -145,6 +143,8 @@ # create properties self.dg_operation_mode = 0 #self.DG_OP_MODE_INIT_POST self.dg_operation_sub_mode = 0 + self.dg_logged_in = False + self.dg_set_logged_in_status(False) # Create command groups self.accel = DGAccelerometer(self.can_interface, self.logger) @@ -173,8 +173,10 @@ self.service_record = DGServiceNVRecord(self.can_interface, self.logger) self.scheduled_runs_record = DGScheduledRunsNVRecord(self.can_interface, self.logger) self.valves = DGValves(self.can_interface, self.logger) + self.voltages = DGVoltages(self.can_interface, self.logger) 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) def get_version(self): """ @@ -208,6 +210,23 @@ """ return self.dg_operation_sub_mode + def get_dg_logged_in(self): + """ + Gets the logged in status of the DG + + @return: True if DG is logged in, False if not + """ + return self.dg_logged_in + + @_publish(["dg_logged_in"]) + def dg_set_logged_in_status(self, logged_in:bool=False): + """ + Callback for DG logged in status change. + @param logged_in boolean logged in status for DG + @return: none + """ + self.dg_logged_in = logged_in + @_publish(["dg_version", "fpga_version"]) def _handler_dg_version(self, message): """ @@ -261,7 +280,7 @@ self.dg_operation_mode = mode[0] self.dg_operation_sub_mode = smode[0] - def cmd_log_in_to_dg(self, resend: bool = False): + def cmd_log_in_to_dg(self, resend: bool = False) -> int: """ Constructs and sends a login command via CAN bus. Login required before \n other commands can be sent to the DG. @@ -282,14 +301,15 @@ if received_message is not None: if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: self.logger.info("Successfully logged in to the DG.") + self.dg_set_logged_in_status(True) else: self.logger.error("Log In Failed.") return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: self.logger.error("Timeout!!!!") return False - def cmd_ui_request_dg_version(self): + def cmd_ui_request_dg_version(self) -> None: """ Constructs and sends the ui request for version message @@ -302,12 +322,10 @@ self.can_interface.send(message, 0) - def cmd_dg_safety_shutdown_override(self): + def cmd_dg_safety_shutdown_override(self) -> int: """ Constructs and sends an DG safety shutdown override command via CAN bus. - \returns response message if received, False if no response received - @return: 1 if successful, zero otherwise """ @@ -329,7 +347,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_dg_software_reset_request(self): + def cmd_dg_software_reset_request(self) -> None: """ Constructs and sends an DG software reset request via CAN bus. Constraints: @@ -346,3 +364,4 @@ # Send message self.can_interface.send(message, 0) self.logger.debug("Sent request to DG to reset...") + self.dg_set_logged_in_status(False) Index: dialin/dg/hd_proxy.py =================================================================== diff -u -rd4cf7e98bfe73fde95043613fa894b64b57d11a8 -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision d4cf7e98bfe73fde95043613fa894b64b57d11a8) +++ dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -105,7 +105,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_drain(self, volume: int = 200, tareLoadCell: bool = False) -> int: + def cmd_drain(self, volume:int=0, tare_load_cell:bool=False) -> int: """ Constructs and sends the drain command. Constraints: @@ -118,7 +118,7 @@ """ vol = integer_to_bytearray(volume) - tare = integer_to_bytearray(tareLoadCell) + tare = integer_to_bytearray(tare_load_cell) payload = vol + tare message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, @@ -161,7 +161,7 @@ message_id=MsgIds.MSG_ID_STARTING_STOPPING_TREATMENT_CMD.value, payload=payload) - self.logger.debug(str+"DG cmd sent to DG") + self.logger.debug(str+" DG cmd sent to DG") # Send message received_message = self.can_interface.send(message) Index: dialin/dg/heat_disinfect.py =================================================================== diff -u -rd4cf7e98bfe73fde95043613fa894b64b57d11a8 -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/dg/heat_disinfect.py (.../heat_disinfect.py) (revision d4cf7e98bfe73fde95043613fa894b64b57d11a8) +++ dialin/dg/heat_disinfect.py (.../heat_disinfect.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -1,11 +1,12 @@ import struct from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..protocols.CAN import DenaliMessage, DenaliChannels from ..utils.base import _AbstractSubSystem, _publish, DialinEnum from logging import Logger from enum import unique + @unique class HeatDisinfectStates(DialinEnum): @@ -35,8 +36,23 @@ @unique -class CancellationModes(DialinEnum): +class HeatDisinfectUIStates(DialinEnum): + HEAT_DISINFECT_UI_STATE_NOT_RUNNING = 0 + HEAT_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT = 1 + HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER = 2 + HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1 = 3 + HEAT_DISINFECT_UI_STATE_TRANSITION_HOT_WATER = 4 + HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_2 = 5 + HEAT_DISINFECT_UI_STATE_COOL_DOWN_DEVICE = 6 + HEAT_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT = 7 + HEAT_DISINFECT_UI_STATE_CANCEL_DISINFECT = 8 + HEAT_DISINFECT_UI_STATE_COMPLETE = 9 + + +@unique +class HeatCancellationModes(DialinEnum): + CANCELLATION_MODE_NONE = 0 CANCELLATION_MODE_BASIC = 1 CANCELLATION_MODE_HOT = 2 @@ -58,9 +74,11 @@ self.logger = logger self.heat_disinfect_state = 0 + self.heat_disinfect_ui_state = 0 self.overall_elapsed_time = 0 self.state_elapsed_time = 0 - self.disinfect_elapsed_time = 0 + self.heat_disinfect_target_time = 0 + self.heat_disinfect_count_down_time = 0 self.cancellation_mode = 0 self.r1_level = 0 self.r2_level = 0 @@ -71,8 +89,29 @@ self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_heat_disinfect_sync) + channel_id = DenaliChannels.dg_to_ui_ch_id + msg_id = MsgIds.MSG_ID_DG_HEAT_DISINFECT_TIME_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_heat_disinfect_to_ui_sync) + + @_publish(["heat_disinfect_target_time", "heat_disinfect_count_down_time"]) + def _handler_heat_disinfect_to_ui_sync(self, message): + """ + Handles published heat disinfect message + + @param message: published heat disinfect UI data message + @returns none + """ + disinfect_target_time = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + disinfect_count_down_time = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + + self.heat_disinfect_target_time = int(disinfect_target_time / 1000) + self.heat_disinfect_count_down_time = disinfect_count_down_time + @_publish(["heat_disinfect_state", "overall_elapsed_time", "state_elapsed_time", "cancellation_mode", "r1_level", - "r2_level"]) + "r2_level", "heat_disinfect_ui_state"]) def _handler_heat_disinfect_sync(self, message): """ Handles published heat disinfect message @@ -86,20 +125,20 @@ message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] state_elapsed_time = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - disinfect_elapsed_time = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] cancellation_mode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] r1 = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] r2 = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + ui = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] self.heat_disinfect_state = state self.overall_elapsed_time = int(elapsed_time / 1000) self.state_elapsed_time = int(state_elapsed_time / 1000) - self.disinfect_elapsed_time = int(disinfect_elapsed_time / 1000) self.cancellation_mode = cancellation_mode - self.r1_level = r1 self.r2_level = r2 + self.heat_disinfect_ui_state = ui + Index: dialin/hd/ui_proxy.py =================================================================== diff -u -r6e20f4690ce887c351d8c65546f93311e5df6ad1 -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- dialin/hd/ui_proxy.py (.../ui_proxy.py) (revision 6e20f4690ce887c351d8c65546f93311e5df6ad1) +++ dialin/hd/ui_proxy.py (.../ui_proxy.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -185,6 +185,14 @@ self._handler_recirc_cmd_response) self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_TX_END_CMD_RESPONSE.value, self._handler_treatment_end_cmd_response) + self.can_interface.\ + register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, + MsgIds.MSG_ID_HD_SET_STANDBY_DISINFECT_SUB_MODE_RESPONSE.value, + self._handler_treatment_end_cmd_response) + self.can_interface.\ + register_receiving_publication_function(DenaliChannels.hd_sync_broadcast_ch_id, + MsgIds.MSG_ID_HD_STANDBY_STATE.value, + self._handler_disinfects_data_publish) # initialize variables that will be populated by HD version response self.hd_version = None @@ -1633,3 +1641,34 @@ self.logger.debug("Sending user disposable removal confirm msg to HD.") self.can_interface.send(message, 0) + def cmd_ui_set_standby_submode_to_disinfect(self) -> None: + """ + Constructs and sends a ui set standby submode to wait for disinfect + + @return: none + """ + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SET_STANDBY_DISINFECT_SUB_MODE_REQUEST.value) + + self.logger.debug("Sending setting standby submode to wait for disinfect to HD.") + self.can_interface.send(message, 0) + + @_publish(["disinfects_hd_submode", "disinfects_dg_mode"]) + def _handler_disinfects_data_publish(self, message: dict) -> None: + """ + Handles published disinfect mode and submode that is published to UI + + @param message: published RO pump data message + + @return: None + """ + dg_submode = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + hd_state = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + + self.disinfects_hd_submode = hd_state + self.disinfects_dg_mode = dg_submode + + Index: tests/peter/test_calibration.py =================================================================== diff -u -r91993c31b1fb88a3937ea9ae4b549d357b53e14e -rf7927c4086e16a080e6ba1552e10f6d776c84e17 --- tests/peter/test_calibration.py (.../test_calibration.py) (revision 91993c31b1fb88a3937ea9ae4b549d357b53e14e) +++ tests/peter/test_calibration.py (.../test_calibration.py) (revision f7927c4086e16a080e6ba1552e10f6d776c84e17) @@ -284,11 +284,13 @@ if __name__ == "__main__": - # test_dg_calibration_record() + test_dg_calibration_record() # test_dg_service_record() # test_dg_system_record() # test_dg_scheduled_runs_record() # test_hd_calibration_record() # test_hd_service_record() + #test_hd_system_record() + # test_crc() # test_hd_system_record()