Index: dialin/common/msg_defs.py =================================================================== diff -u -r8ea13ae6dd10732bfcc456798f4785c4d88c95d3 -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/common/msg_defs.py (.../msg_defs.py) (revision 8ea13ae6dd10732bfcc456798f4785c4d88c95d3) +++ dialin/common/msg_defs.py (.../msg_defs.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -75,6 +75,9 @@ MSG_ID_DG_HEAT_DISINFECT_DATA = 0x37 # DG heat disinfection publish data MSG_ID_UI_START_TREATMENT = 0x38 # UI user request to initiate a treatment MSG_ID_HD_START_TREATMENT_RESPONSE = 0x39 # HD response to user request to initiate a treatment + MSG_ID_DG_UV_REACTORS_DATA = 0x44 # DG UV reactors publish data + MSG_ID_DG_THERMISTORS_DATA = 0x45 # DG thermistors publish data + MSG_ID_DG_FANS_DATA = 0x48 # DG fans publish data MSG_ID_CAN_ERROR_COUNT = 0x999 # test code in support of EMC testing @@ -161,6 +164,13 @@ MSG_ID_HEAT_DISINFECT_RSRVR2_TO_RSRVR1_DURATION_MINS = 0xA01F # Heat disinfection reservoir 2 to reservoir 1 duration in minutes MSG_ID_HEAT_DISINFECT_NO_OF_CYCLES_TO_RUN = 0xA020 # Heat disinfection number of cycles to run MSG_ID_HEAT_DISINFECT_PUBLISH_INTERVAL_OVERRIDE = 0xA021 # Heat disinfection data publish interval override request + MSG_ID_UV_REACTORS_DATA_PUBLISH_INTERVAL_OVERRIDE = 0xA025 # UV reactors data publish interval override + MSG_ID_DG_START_STOP_INLET_UV_REACTOR = 0xA028 # DG start/stop inlet UV reactor + MSG_ID_DG_FANS_DATA_PUBLISH_OVERRIDE = 0xA02A # Fans data publish interval override request + MSG_ID_DG_START_STOP_OUTLET_UV_REACTOR = 0xA02B # DG start/stop outlet UV reactor + MSG_ID_DG_UV_REACTORS_HEALTH_OVERRIDE = 0xA02C # DG UV reactors health override request + MSG_ID_DG_THERMISTORS_DATA_PUBLISH_INTERVAL_OVERRIDE = 0xA02D # DG thermistors data publish interval override + MSG_ID_DG_THERMISTORS_VALUE_OVERRIDE = 0xA02E # DG thermistors value override MSG_ID_HD_DEBUG_EVENT = 0xFFF1 # HD debug event text to be logged in event log MSG_ID_DG_DEBUG_EVENT = 0xFFF2 # DG debug event text to be logged in event log Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -ra2add7d5c768ab21eba0c61e5ec5c7e84b75eeab -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision a2add7d5c768ab21eba0c61e5ec5c7e84b75eeab) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -26,6 +26,10 @@ from .heaters import Heaters from .temperature_sensors import TemperatureSensors from .conductivity_sensors import ConductivitySensors +from .heat_disinfection import HeatDisinfection +from .thermistors import Thermistors +from .fans import Fans +from .uv_reactors import UVReactors from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish, _LogManager @@ -148,6 +152,10 @@ self.temperature_sensors = TemperatureSensors(self.can_interface, self.logger) self.conductivity_sensors = ConductivitySensors(self.can_interface, self.logger) self.alarms = DGAlarms(self.can_interface, self.logger) + self.heat_disinfect = HeatDisinfection(self.can_interface, self.logger) + self.thermistors = Thermistors(self.can_interface, self.logger) + self.fans = Fans(self.can_interface, self.logger) + self.uv_reactors = UVReactors(self.can_interface, self.logger) def get_version(self): """ Index: dialin/dg/drain_pump.py =================================================================== diff -u -ra2add7d5c768ab21eba0c61e5ec5c7e84b75eeab -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/dg/drain_pump.py (.../drain_pump.py) (revision a2add7d5c768ab21eba0c61e5ec5c7e84b75eeab) +++ dialin/dg/drain_pump.py (.../drain_pump.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -16,12 +16,21 @@ import struct from ..utils.conversions import integer_to_bytearray from .constants import RESET, NO_RESET -from ..protocols.CAN import (DenaliMessage, - DenaliChannels) +from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +import enum +class DrainPumpStates(enum.Enum): + DRAIN_PUMP_OFF_STATE = 0 + DRAIN_PUMP_CONTROL_TO_TARGET_STATE = 1 + DRAIN_PUMP_OPEN_LOOP_STATE = 2 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + class DGDrainPump(_AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for drain pump related commands. @@ -37,6 +46,10 @@ END_POS_SET_SPD = START_POS_SET_SPD + 4 START_POS_DAC = END_POS_SET_SPD END_POS_DAC = START_POS_DAC + 4 + START_POS_PRESS_DIFF = END_POS_DAC + END_POS_PRESS_DIFF = START_POS_PRESS_DIFF + 4 + START_POS_PUMP_STATE = END_POS_PRESS_DIFF + END_POS_PUMP_STATE = START_POS_PUMP_STATE + 4 def __init__(self, can_interface, logger: Logger): """ @@ -52,16 +65,18 @@ self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_drain_pump_sync) - self.target_drain_pump_speed_RPM = 0 + self.target_drain_pump_RPM = 0 self.dac_value = 0 + self.pressure_difference = 0 + self.drain_pump_state = 0 def get_target_drain_pump_speed(self): """ Gets the target drain pump speed @return: The target drain pump speed (RPM) """ - return self.target_drain_pump_speed_RPM + return self.target_drain_pump_RPM def get_dac_value(self): """ @@ -70,7 +85,7 @@ """ return self.dac_value - @_publish(["target_drain_pump_speed_RPM", "dac_value"]) + @_publish(["target_drain_pump_RPM", "dac_value", "pressure_difference", "drain_pump_state"]) def _handler_drain_pump_sync(self, message): """ Handles published drain pump data messages. Drain pump data are captured @@ -81,12 +96,18 @@ """ tgt = struct.unpack('i', bytearray( - message['message'][self.START_POS_SET_SPD:self.END_POS_SET_SPD])) + message['message'][self.START_POS_SET_SPD:self.END_POS_SET_SPD]))[0] dac = struct.unpack('i', bytearray( - message['message'][self.START_POS_DAC:self.END_POS_DAC])) + message['message'][self.START_POS_DAC:self.END_POS_DAC]))[0] + diff = struct.unpack('f', bytearray( + message['message'][self.START_POS_PRESS_DIFF:self.END_POS_PRESS_DIFF]))[0] + state = struct.unpack('i', bytearray( + message['message'][self.START_POS_PUMP_STATE:self.END_POS_PUMP_STATE]))[0] - self.target_drain_pump_speed_RPM = tgt[0] - self.dac_value = dac[0] + self.target_drain_pump_RPM = tgt + self.dac_value = dac + self.pressure_difference = diff + self.drain_pump_state = state def cmd_drain_pump_speed_set_point_override(self, speed, reset=NO_RESET): """ Index: dialin/dg/fans.py =================================================================== diff -u --- dialin/dg/fans.py (revision 0) +++ dialin/dg/fans.py (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -0,0 +1,142 @@ + +import struct +from ..utils.conversions import integer_to_bytearray +from .constants import NO_RESET, RESET +from ..common.msg_defs import MsgIds +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish +from logging import Logger +import enum + + +class FansNames(enum.Enum): + + FAN_INLET_1 = 0 + FAN_INLET_2 = 1 + FAN_INLET_3 = 2 + FAN_OUTLET_1 = 3 + FAN_OUTLET_2 = 4 + FAN_OUTLET_3 = 5 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class Fans(_AbstractSubSystem): + """ + Dialysate Generator (DG) Dialin API sub-class for fans related commands. + """ + START_POS_TARGET_PWM = DenaliMessage.PAYLOAD_START_INDEX + END_POS_TARGET_PWM = START_POS_TARGET_PWM + 4 + + START_POS_INLET_1_RPM = END_POS_TARGET_PWM + END_POS_INLET_1_RPM = START_POS_INLET_1_RPM + 4 + START_POS_INLET_2_RPM = END_POS_INLET_1_RPM + END_POS_INLET_2_RPM = START_POS_INLET_2_RPM + 4 + START_POS_INLET_3_RPM = END_POS_INLET_2_RPM + END_POS_INLET_3_RPM = START_POS_INLET_3_RPM + 4 + + START_POS_OUTLET_1_RPM = END_POS_INLET_3_RPM + END_POS_OUTLET_1_RPM = START_POS_OUTLET_1_RPM + 4 + START_POS_OUTLET_2_RPM = END_POS_OUTLET_1_RPM + END_POS_OUTLET_2_RPM = START_POS_OUTLET_2_RPM + 4 + START_POS_OUTLET_3_RPM = END_POS_OUTLET_2_RPM + END_POS_OUTLET_3_RPM = START_POS_OUTLET_3_RPM + 4 + + def __init__(self, can_interface, logger: Logger): + """ + + @param can_interface: Denali CAN Messenger object + """ + + 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_FANS_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_fans_sync) + + # Publish variables + self.target_pwm = 0 + self.inlet_1_rpm = 0 + self.inlet_2_rpm = 0 + self.inlet_3_rpm = 0 + self.outlet_1_rpm = 0 + self.outlet_2_rpm = 0 + self.outlet_3_rpm = 0 + + @_publish(['target_pwm', 'inlet_1_rpm', 'inlet_2_rpm', 'inlet_3_rpm', 'outlet_1_rpm', 'outlet_2_rpm', + 'outlet_3_rpm']) + def _handler_fans_sync(self, message): + """ + Handles published thermistors message. + + @param message: published thermistors message + @return: none + """ + tgt_pwm = struct.unpack('f', bytearray( + message['message'][self.START_POS_TARGET_PWM:self.END_POS_TARGET_PWM]))[0] + inlet_1_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_INLET_1_RPM:self.END_POS_INLET_1_RPM]))[0] + inlet_2_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_INLET_2_RPM:self.END_POS_INLET_2_RPM]))[0] + inlet_3_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_INLET_3_RPM:self.END_POS_INLET_3_RPM]))[0] + outlet_1_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_OUTLET_1_RPM:self.END_POS_OUTLET_1_RPM]))[0] + outlet_2_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_OUTLET_2_RPM:self.END_POS_OUTLET_2_RPM]))[0] + outlet_3_rpm = struct.unpack('f', bytearray( + message['message'][self.START_POS_OUTLET_3_RPM:self.END_POS_OUTLET_3_RPM]))[0] + + self.target_pwm = tgt_pwm + self.inlet_1_rpm = inlet_1_rpm + self.inlet_2_rpm = inlet_2_rpm + self.inlet_3_rpm = inlet_3_rpm + self.outlet_1_rpm = outlet_1_rpm + self.outlet_2_rpm = outlet_2_rpm + self.outlet_3_rpm = outlet_3_rpm + + def cmd_fans_data_broadcast_interval_override(self, ms, reset=NO_RESET): + """ + Constructs and sends the fans data publish interval. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 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 + """ + + 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_FANS_DATA_PUBLISH_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override fans data publish 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( + "Fans 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 \ No newline at end of file Index: dialin/dg/hd_proxy.py =================================================================== diff -u -rfdac759dbbec54375d4b3ebb21aebcc684ac1aed -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision fdac759dbbec54375d4b3ebb21aebcc684ac1aed) +++ dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -33,8 +33,6 @@ MSG_ID_HD_START_STOP_DG_CMD = 0x0026 MSG_ID_HD_START_STOP_DG_TRIMMER_HEATER = 0x002B - MSG_ID_DG_START_STOP_HEAT_DISINFECT = 0x30 - # Reservoir IDs RESERVOIR1 = 0 RESERVOIR2 = 1 @@ -214,38 +212,6 @@ self.logger.debug("Timeout!!!!") return False - def cmd_start_heat_disinfection(self): - """ - Constructs and sends start heat disinfect command - Constraints: - N/A - - @returns none - """ - # 1 is to start - payload = integer_to_bytearray(1) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, - message_id=self.MSG_ID_DG_START_STOP_HEAT_DISINFECT, - payload=payload) - print("Starting heat disinfection process") - received_message = self.can_interface.send(message) - - def cmd_stop_heat_disinfection(self): - """ - Constructs and sends stop heat disinfect command - Constraints: - N/A - - @returns none - """ - # 1 is to start - payload = integer_to_bytearray(0) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, - message_id=self.MSG_ID_DG_START_STOP_HEAT_DISINFECT, - payload=payload) - print("Stopping heat disinfection process") - received_message = self.can_interface.send(message) - def cmd_stop_primary_heater(self): """ Constructs and sends stop heat disinfect command Index: dialin/dg/heat_disinfection.py =================================================================== diff -u --- dialin/dg/heat_disinfection.py (revision 0) +++ dialin/dg/heat_disinfection.py (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -0,0 +1,124 @@ + +import struct +from ..utils.conversions import integer_to_bytearray +from ..utils.conversions import float_to_bytearray #TODO remove +from .constants import NO_RESET +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish +from logging import Logger +import enum + + +class HeatDisinfectionStates(enum.Enum): + + DG_HEAT_DISINFECT_STATE_START = 0 + DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER = 1 + DG_HEAT_DISINFECT_STATE_HEAT_WATER = 2 + DG_HEAT_DISINFECT_STATE_DISINFECT_RECIRC_PATH = 3 + DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_1_TO_2 = 4 + DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_2_TO_1 = 5 + DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH = 6 + DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIR = 7 + DG_HEAT_DISINFECT_STATE_COMPLETE = 8 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class HeatDisinfectionInternalStates(enum.Enum): + + INTERNAL_HEAT_DISINFECT_STATE_OFF = 0 + INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER = 1 + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH = 2 + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1 = 3 + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_2 =4 + INTERNAL_HEAT_DISINFECT_STATE_COMPLETE = 5 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class HeatDisinfection(_AbstractSubSystem): + """ + \class HeatDisinfection + + \brief Heat disinfection class with APIs to set the timing of each of the stages. + """ + MSG_ID_DG_START_STOP_HEAT_DISINFECT = 0x30 + MSG_ID_DG_HEAT_DISINFECT_DATA = 0x37 + + START_POS_INTERNAL_STATE = DenaliMessage.PAYLOAD_START_INDEX + END_POS_INTERNAL_STATE = START_POS_INTERNAL_STATE + 4 + START_POS_ELAPSED_TIME = END_POS_INTERNAL_STATE + END_POS_ELAPSED_TIME = START_POS_ELAPSED_TIME + 4 + START_POS_CURRENT_CYCLE = END_POS_ELAPSED_TIME + END_POS_CURRENT_CYCLE = START_POS_CURRENT_CYCLE + 4 + + def __init__(self, can_interface, logger: Logger): + + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + self.internal_state = 0 + self.elapsed_time = 0 + self.current_cycle_count = 0 + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_HEAT_DISINFECT_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_heat_disinfect_sync) + + @_publish(["internal_state", "elapsed_time", "current_cycle_count"]) + def _handler_heat_disinfect_sync(self, message): + """ + Handles published heat disinfection message + + @param message: published heat disinfection data message + @returns none + """ + internal_state = struct.unpack('i', bytearray( + message['message'][self.START_POS_INTERNAL_STATE:self.END_POS_INTERNAL_STATE]))[0] + elapsed_time = struct.unpack('f', bytearray( + message['message'][self.START_POS_ELAPSED_TIME:self.END_POS_ELAPSED_TIME]))[0] + current_cycle = struct.unpack('i', bytearray( + message['message'][self.START_POS_CURRENT_CYCLE:self.END_POS_CURRENT_CYCLE]))[0] + + self.internal_state = internal_state + self.elapsed_time = elapsed_time + self.current_cycle_count = current_cycle + + def cmd_start_stop_heat_disinfection(self, start=True): + """ + Constructs and sends the start/stop DG heat disinfection command + + @param start: boolean - True = start heat disinfection, False = stop heat disinfection. + @return: non-zero integer if successful, False otherwise + """ + # 1 is to start + if start: + cmd = 1 + str = "Starting" + else: + cmd = 0 + str = "Stopping" + payload = integer_to_bytearray(cmd) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_START_STOP_HEAT_DISINFECT, + payload=payload) + + self.logger.debug(str + " DG heat disinfection") + + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False Index: dialin/dg/ro_pump.py =================================================================== diff -u -ra2add7d5c768ab21eba0c61e5ec5c7e84b75eeab -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/dg/ro_pump.py (.../ro_pump.py) (revision a2add7d5c768ab21eba0c61e5ec5c7e84b75eeab) +++ dialin/dg/ro_pump.py (.../ro_pump.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -16,12 +16,24 @@ import struct from ..utils.conversions import integer_to_bytearray, float_to_bytearray from .constants import RESET, NO_RESET -from ..protocols.CAN import (DenaliMessage, - DenaliChannels) +from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +import enum +class ROPumpStates(enum.Enum): + RO_PUMP_OFF_STATE = 0 + RO_PUMP_RAMP_UP_STATE = 1 + RO_PUMP_VERIFY_FLOW_STATE = 2 + RO_PUMP_CONTROL_TO_TARGET_STATE = 3 + RO_PUMP_OPEN_LOOP_STATE = 4 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + class DGROPump(_AbstractSubSystem): """ DGROPump @@ -30,7 +42,7 @@ """ # RO pump message IDs - MSG_ID_DG_RO_PUMP_PUBLISHED_DATA = 0x001F + MSG_ID_DG_RO_PUMP_PUBLISHED_DATA = 0x1F MSG_ID_DG_RO_PUMP_PRESSURE_SET_PT_OVERRIDE = 0xA008 #MSG_ID_DG_RO_FLOW_RATE_OVERRIDE = 0xA009 MSG_ID_DG_RO_PUMP_BROADCAST_INTERVAL_OVERRIDE = 0xA00A @@ -46,10 +58,6 @@ START_POS_STATE = END_POS_PWM END_POS_STATE = START_POS_STATE + 4 - #Enums - RAMP_UP_STATE = 0 - - def __init__(self, can_interface, logger: Logger): """ DGROPump constructor @@ -62,10 +70,9 @@ if self.can_interface is not None: channel_id = DenaliChannels.dg_sync_broadcast_ch_id msg_id = self.MSG_ID_DG_RO_PUMP_PUBLISHED_DATA - self.can_interface.register_receiving_publication_function(channel_id, msg_id, - self._handler_ro_pump_sync) + self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_ro_pump_sync) - self.target_pressure_psi = 0 + self.target_pressure_psi = 0.0 self.measured_flow_rate_lpm = 0.0 self.pwm_duty_cycle_pct = 0.0 self.ro_pump_state = 0.0 @@ -91,48 +98,28 @@ """ return self.pwm_duty_cycle_pct - @_publish([ - "target_pressure_psi", - "measured_flow_rate_lpm", - "pwm_duty_cycle_pct", - "ro_pump_state" - ]) + @_publish(["target_pressure_psi", "measured_flow_rate_lpm", "pwm_duty_cycle_pct", "ro_pump_state"]) def _handler_ro_pump_sync(self, message): """ Handles published ro pump data messages. RO pump data are captured for reference. @param message: published RO pump data message + @return: None """ + tgt = struct.unpack('f', bytearray(message['message'][self.START_POS_PRES_SET_PT:self.END_POS_PRES_SET_PT]))[0] + flow = struct.unpack('f', bytearray(message['message'][self.START_POS_MEAS_FLOW:self.END_POS_MEAS_FLOW]))[0] + pwm = struct.unpack('f', bytearray(message['message'][self.START_POS_PWM:self.END_POS_PWM]))[0] + ro_state = struct.unpack('i', bytearray(message['message'][self.START_POS_STATE:self.END_POS_STATE]))[0] - tgt = struct.unpack('f', bytearray( - message['message'][self.START_POS_PRES_SET_PT:self.END_POS_PRES_SET_PT])) - flow = struct.unpack('f', bytearray( - message['message'][self.START_POS_MEAS_FLOW:self.END_POS_MEAS_FLOW])) - pwm = struct.unpack('f', bytearray( - message['message'][self.START_POS_PWM:self.END_POS_PWM])) - ro_state = struct.unpack('i', bytearray( - message['message'][self.START_POS_STATE:self.END_POS_STATE])) + self.target_pressure_psi = tgt + self.measured_flow_rate_lpm = flow + self.pwm_duty_cycle_pct = pwm - self.target_pressure_psi = tgt[0] - self.measured_flow_rate_lpm = flow[0] - self.pwm_duty_cycle_pct = pwm[0] - raw_ro_pump_state = ro_state[0] + if ROPumpStates.has_value(ro_state): + self.ro_pump_state = ROPumpStates(ro_state).name - #self.ro_pump_state = self.ro_pump_states.get("RO_PUMP_OFF_STATE", -1) - - if raw_ro_pump_state == 0: - self.ro_pump_state = "RO_PUMP_OFF_STATE" - elif raw_ro_pump_state == 1: - self.ro_pump_state = "RO_PUMP_RAMP_UP_STATE" - elif raw_ro_pump_state == 2: - self.ro_pump_state = "RO_PUMP_VERIFY_FLOW_STATE" - elif raw_ro_pump_state == 3: - self.ro_pump_state = "RO_PUMP_CONTROL_TO_TARGET_STATE" - elif raw_ro_pump_state == 4: - self.ro_pump_state = "RO_PUMP_OPEN_LOOP_STATE" - def cmd_ro_pump_set_point_override(self, pressure, reset=NO_RESET): """ Constructs and sends the RO pump set point override command. Index: dialin/dg/thermistors.py =================================================================== diff -u --- dialin/dg/thermistors.py (revision 0) +++ dialin/dg/thermistors.py (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -0,0 +1,182 @@ + +import struct +from ..common.msg_defs import MsgIds +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish +from ..utils.conversions import integer_to_bytearray +from .constants import RESET, NO_RESET +from logging import Logger +import enum + + +class ThermistorsNames(enum.Enum): + + THERMISTOR_ONBOARD_NTC = 0 + TEMPSENSOR_FPGA_SENSOR = 1 + TEMPSENSOR_LOAD_CELL_A1_B1 = 2 + TEMPSENSOR_LOAD_CELL_A2_B2 = 3 + TEMPSENSOR_INTERNAL_THDO_RTD = 4 + TEMPSENSOR_INTERNAL_TDI_RTD = 5 + TEMPSENSOR_INTERNAL_CONDUCTIVITY = 6 + THERMISTOR_POWER_SUPPLY_1 = 7 + THERMISTOR_POWER_SUPPLY_2 = 8 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class Thermistors(_AbstractSubSystem): + """ + Dialysate Generation (DG) interface for thermistors and board temperature sensors related commands. + """ + + # Publish message field positions + START_POS_ONBOARD_TEMP = DenaliMessage.PAYLOAD_START_INDEX + END_POS_ONBOARD_TEMP = START_POS_ONBOARD_TEMP + 4 + START_POS_FPGA_SENSOR = END_POS_ONBOARD_TEMP + END_POS_FPGA_SENSOR = START_POS_FPGA_SENSOR + 4 + START_POS_LOAD_CELL_A1_B1 = END_POS_FPGA_SENSOR + END_POS_LOAD_CELL_A1_B1 = START_POS_LOAD_CELL_A1_B1 + 4 + START_POS_LOAD_CELL_A2_B2 = END_POS_LOAD_CELL_A1_B1 + END_POS_LOAD_CELL_A2_B2 = START_POS_LOAD_CELL_A2_B2 + 4 + START_POS_THDO_RTD = END_POS_LOAD_CELL_A2_B2 + END_POS_THDO_RTD = START_POS_THDO_RTD + 4 + START_POS_TDI_RTD = END_POS_THDO_RTD + END_POS_TDI_RTD = START_POS_TDI_RTD + 4 + START_POS_INTRNL_CONDUCTIVITY = END_POS_TDI_RTD + END_POS_INTRNL_CONDUCTIVITY = START_POS_INTRNL_CONDUCTIVITY + 4 + START_POS_PWR_SUPPLY_1 = END_POS_INTRNL_CONDUCTIVITY + END_POS_PWR_SUPPLY_1 = START_POS_PWR_SUPPLY_1 + 4 + START_POS_PWR_SUPPLY_2 = END_POS_PWR_SUPPLY_1 + END_POS_PWR_SUPPLY_2 = START_POS_PWR_SUPPLY_2 + 4 + + def __init__(self, can_interface, logger: Logger): + """ + + @param can_interface: Denali CAN Messenger object + """ + + 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_THERMISTORS_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_thermistors_sync) + + # Dictionary of the thermistors + self.thermistors = {ThermistorsNames.THERMISTOR_ONBOARD_NTC.name: {}, + ThermistorsNames.TEMPSENSOR_FPGA_SENSOR.name: {}, + ThermistorsNames.TEMPSENSOR_LOAD_CELL_A1_B1.name: {}, + ThermistorsNames.TEMPSENSOR_LOAD_CELL_A2_B2.name: {}, + ThermistorsNames.TEMPSENSOR_INTERNAL_THDO_RTD.name: {}, + ThermistorsNames.TEMPSENSOR_INTERNAL_TDI_RTD.name: {}, + ThermistorsNames.TEMPSENSOR_INTERNAL_CONDUCTIVITY.name: {}, + ThermistorsNames.THERMISTOR_POWER_SUPPLY_1.name: {}, + ThermistorsNames.THERMISTOR_POWER_SUPPLY_2.name: {}} + + @_publish(['thermistors']) + def _handler_thermistors_sync(self, message): + """ + Handles published thermistors message. + + @param message: published thermistors message + @return: none + """ + onboard_temp = struct.unpack('f', bytearray( + message['message'][self.START_POS_ONBOARD_TEMP:self.END_POS_ONBOARD_TEMP]))[0] + fpga_temp = struct.unpack('f', bytearray( + message['message'][self.START_POS_FPGA_SENSOR:self.END_POS_FPGA_SENSOR]))[0] + ld_cell_a1 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LOAD_CELL_A1_B1:self.END_POS_LOAD_CELL_A1_B1]))[0] + ld_cell_a2 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LOAD_CELL_A2_B2:self.END_POS_LOAD_CELL_A2_B2]))[0] + thdo_rtd = struct.unpack('f', bytearray( + message['message'][self.START_POS_THDO_RTD:self.END_POS_THDO_RTD]))[0] + tdi_rtd = struct.unpack('f', bytearray( + message['message'][self.START_POS_TDI_RTD:self.END_POS_TDI_RTD]))[0] + conductivity = struct.unpack('f', bytearray( + message['message'][self.START_POS_INTRNL_CONDUCTIVITY:self.END_POS_INTRNL_CONDUCTIVITY]))[0] + pwr_supply_1 = struct.unpack('f', bytearray( + message['message'][self.START_POS_PWR_SUPPLY_1:self.END_POS_PWR_SUPPLY_1]))[0] + pwr_supply_2 = struct.unpack('f', bytearray( + message['message'][self.START_POS_PWR_SUPPLY_2:self.END_POS_PWR_SUPPLY_2]))[0] + + self.thermistors[ThermistorsNames.THERMISTOR_ONBOARD_NTC.name] = onboard_temp + self.thermistors[ThermistorsNames.TEMPSENSOR_FPGA_SENSOR.name] = fpga_temp + self.thermistors[ThermistorsNames.TEMPSENSOR_LOAD_CELL_A1_B1.name] = ld_cell_a1 + self.thermistors[ThermistorsNames.TEMPSENSOR_LOAD_CELL_A2_B2.name] = ld_cell_a2 + self.thermistors[ThermistorsNames.TEMPSENSOR_INTERNAL_THDO_RTD.name] = thdo_rtd + self.thermistors[ThermistorsNames.TEMPSENSOR_INTERNAL_TDI_RTD.name] = tdi_rtd + self.thermistors[ThermistorsNames.TEMPSENSOR_INTERNAL_CONDUCTIVITY.name] = conductivity + self.thermistors[ThermistorsNames.THERMISTOR_POWER_SUPPLY_1.name] = pwr_supply_1 + self.thermistors[ThermistorsNames.THERMISTOR_POWER_SUPPLY_2.name] = pwr_supply_2 + + def cmd_thermistors_value_override(self, thermistor, value, reset=NO_RESET): + """ + Constructs and sends the thermistors value override command + + @param thermistor: integer - thermistor index + @param value: float the temperature to be set + """ + reset_value = integer_to_bytearray(reset) + thr = integer_to_bytearray(thermistor) + vlu = integer_to_bytearray(value) + payload = reset_value + thr + vlu + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_DG_THERMISTORS_VALUE_OVERRIDE.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Themristors value override Timeout!!!") + return False + + def cmd_thermistors_data_broadcast_interval_override(self, ms, reset=NO_RESET): + """ + Constructs and sends the thermistors data publish interval command. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 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 + """ + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + id = MsgIds.MSG_ID_DG_THERMISTORS_DATA_PUBLISH_INTERVAL_OVERRIDE.value + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=id, + payload=payload) + + self.logger.debug("Overriding themistors 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( + "Thermistors 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 \ No newline at end of file Index: dialin/dg/uv_reactors.py =================================================================== diff -u --- dialin/dg/uv_reactors.py (revision 0) +++ dialin/dg/uv_reactors.py (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -0,0 +1,218 @@ + +import struct +from ..utils.conversions import integer_to_bytearray +from .constants import NO_RESET, RESET +from ..common.msg_defs import MsgIds +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish +from logging import Logger +import enum + + +class ReactorsNames(enum.Enum): + + INLET_UV_REACTOR = 0 + OUTLET_UV_REACTOR = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class ReactorsStates(enum.Enum): + + UV_REACTOR_STATE_OFF = 0 + UV_REACTOR_STATE_ON = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + +class UVReactors(_AbstractSubSystem): + """ + Dialysate Generator (DG) Dialin API sub-class for UV reactors related commands. + """ + START_POS_INLET_REACTOR_HEALTH = DenaliMessage.PAYLOAD_START_INDEX + END_POS_INLET_REACTOR_HEALTH = START_POS_INLET_REACTOR_HEALTH + 4 + + START_POS_OUTLET_REACTOR_HEALTH = END_POS_INLET_REACTOR_HEALTH + END_POS_OUTLET_REACTOR_HEALTH = START_POS_OUTLET_REACTOR_HEALTH + 4 + + START_POS_INLET_REACTOR_STATE = END_POS_OUTLET_REACTOR_HEALTH + END_POS_INLET_REACTOR_STATE = START_POS_INLET_REACTOR_STATE + 4 + + START_POS_OUTLET_REACTOR_STATE = END_POS_INLET_REACTOR_STATE + END_POS_OUTLET_REACTOR_STATE = START_POS_OUTLET_REACTOR_STATE + 4 + + def __init__(self, can_interface, logger: Logger): + """ + + @param can_interface: Denali CAN Messenger object + """ + + 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_UV_REACTORS_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_uv_reactors_sync) + + self.inlet_uv_reactor_health = 0.0 + self.outlet_uv_reactor_health = 0.0 + self.inlet_uv_reactor_state = 0.0 + self.outlet_uv_reactor_state = 0.0 + + @_publish(['inlet_uv_reactor_health', 'outlet_uv_reactor_health', 'inlet_uv_reactor_state', + 'outlet_uv_reactor_state']) + def _handler_uv_reactors_sync(self, message): + """ + Handles published thermistors message. + + @param message: published thermistors message + @return: none + """ + inlet_health = struct.unpack('f', bytearray( + message['message'][self.START_POS_INLET_REACTOR_HEALTH:self.END_POS_INLET_REACTOR_HEALTH]))[0] + outlet_health = struct.unpack('f', bytearray( + message['message'][self.START_POS_OUTLET_REACTOR_HEALTH:self.END_POS_OUTLET_REACTOR_HEALTH]))[0] + inlet_state = struct.unpack('f', bytearray( + message['message'][self.START_POS_INLET_REACTOR_STATE:self.END_POS_INLET_REACTOR_STATE]))[0] + outlet_state = struct.unpack('f', bytearray( + message['message'][self.START_POS_OUTLET_REACTOR_STATE:self.END_POS_OUTLET_REACTOR_STATE]))[0] + + self.inlet_uv_reactor_health = inlet_health + self.outlet_uv_reactor_health = outlet_health + + # Check if the received state from firmware is in range otherwise, the state will be unknown + self.inlet_uv_reactor_state = ReactorsStates(inlet_state).name if ReactorsStates.has_value(inlet_state)\ + else 'Inlet UV reactor state unknown' + + self.outlet_uv_reactor_state = ReactorsStates(outlet_state).name if ReactorsStates.has_value(outlet_state)\ + else 'Outlet UV reactor state unknown' + + def cmd_uv_reactors_data_broadcast_interval_override(self, ms, reset=NO_RESET): + """ + Constructs and sends the UV reactors data publish interval. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 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 + """ + + 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_UV_REACTORS_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override UV reactors data publish 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( + "UV reactors 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 + + def cmd_uv_reactors_health_override(self, reactor, health, reset=NO_RESET): + """ + Constructs and sends the UV reactors' health override command + + @param reactor: integer - UV reactor index + @param health: integer - health to be set ot + """ + reset_value = integer_to_bytearray(reset) + rctr = integer_to_bytearray(reactor) + hlth = integer_to_bytearray(health) + payload = reset_value + rctr + hlth + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_DG_UV_REACTORS_HEALTH_OVERRIDE.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("UV reactors health override Timeout!!!") + return False + + def cmd_start_stop_inlet_uv_reactor(self, state=ReactorsStates.UV_REACTOR_STATE_OFF.name): + """ + Constructs and sends a start/stop command to the DG inlet UV reactor + + \returns 1 if successful, zero otherwise + """ + if state == ReactorsStates.UV_REACTOR_STATE_ON: + payload = integer_to_bytearray(1) + operation = 'Turning on ' + else: + payload = integer_to_bytearray(0) + operation = 'Turning off ' + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_DG_START_STOP_INLET_UV_REACTOR.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + self.logger.debug(operation + "inlet UV reactor") + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug(operation + "inlet UV reactor timeout!!") + return False + + def cmd_start_stop_outlet_uv_reactor(self, state=ReactorsStates.UV_REACTOR_STATE_OFF.name): + """ + Constructs and sends a start/stop command to the DG outlet UV reactor + + \returns 1 if successful, zero otherwise + """ + if state == ReactorsStates.UV_REACTOR_STATE_ON: + payload = integer_to_bytearray(1) + operation = 'Turning on ' + else: + payload = integer_to_bytearray(0) + operation = 'Turning off ' + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_DG_START_STOP_OUTLET_UV_REACTOR.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + self.logger.debug(operation + "outlet UV reactor") + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug(operation + "outlet UV reactor timeout!!") + return False \ No newline at end of file Index: dialin/dg/valves.py =================================================================== diff -u -ra2add7d5c768ab21eba0c61e5ec5c7e84b75eeab -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- dialin/dg/valves.py (.../valves.py) (revision a2add7d5c768ab21eba0c61e5ec5c7e84b75eeab) +++ dialin/dg/valves.py (.../valves.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -20,12 +20,66 @@ from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +import enum # Valve states ENERGIZED = True DEENERGIZED = False +class VPiVSPVBfStates(enum.Enum): + VALVE_STATE_CLOSED = 0 + VALVE_STATE_OPEN = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +class VPdStates(enum.Enum): + + VALVE_STATE_OPEN_C_TO_NO = 0 + VALVE_STATE_DRAIN_C_TO_NC = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +class VPoStates(enum.Enum): + + VALVE_STATE_NOFILL_C_TO_NO = 0 + VALVE_STATE_FILL_C_TO_NC = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +class VDrVRcStates(enum.Enum): + + VALVE_STATE_DRAIN_C_TO_NO = 0 + VALVE_STATE_RECIRC_C_TO_NC = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +class VRoVRiStates(enum.Enum): + + VALVE_STATE_R1_C_TO_NO = 0 + VALVE_STATE_R2_C_TO_NC = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +class VRdVRfStates(enum.Enum): + + VALVE_STATE_R2_C_TO_NO = 0 + VALVE_STATE_R1_C_TO_NC = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + class DGValves(_AbstractSubSystem): """ Dialysate Generation (DG) interface for valve related commands. @@ -54,6 +108,7 @@ VALVE_RESERVOIR_1 = 10 # VR1 VALVE_RESERVOIR_2 = 11 # VR2 VALVE_PRODUCTION_DRAIN = 12 # VPD + NUM_OF_VALVES = 13 # Number of valves def __init__(self, can_interface, logger: Logger): """ @@ -85,6 +140,8 @@ self.valve_state_VR2 = {"id": self.VALVE_RESERVOIR_2, "state": DEENERGIZED} self.valve_state_VPD = {"id": self.VALVE_PRODUCTION_DRAIN, "state": DEENERGIZED} + self.valve_states_enum = [0 for i in range(self.NUM_OF_VALVES)] + def get_valve_states(self): """ Gets the valve states @@ -199,7 +256,8 @@ "valve_state_VSP", "valve_state_VR1", "valve_state_VR2", - "valve_state_VPD" + "valve_state_VPD", + "valve_states_enum" ]) def _handler_valves_sync(self, message): """ @@ -226,6 +284,20 @@ self.valve_state_VR2["state"] = self._binary_to_valve_state(vst[0] & 2048) self.valve_state_VPD["state"] = self._binary_to_valve_state(vst[0] & 4096) + self.valve_states_enum[self.VALVE_RESERVOIR_FILL] = VRdVRfStates(self._binary_to_valve_state(vst[0] & 1)).name # VRF + self.valve_states_enum[self.VALVE_RESERVOIR_INLET] = VRoVRiStates(self._binary_to_valve_state(vst[0] & 2)).name # VRI + self.valve_states_enum[self.VALVE_RESERVOIR_DRAIN] = VRdVRfStates(self._binary_to_valve_state(vst[0] & 4)).name # VRD + self.valve_states_enum[self.VALVE_RESERVOIR_OUTLET] = VRoVRiStates(self._binary_to_valve_state(vst[0] & 8)).name # VRO + self.valve_states_enum[self.VALVE_PRESSURE_OUTLET] = VPoStates(self._binary_to_valve_state(vst[0] & 16)).name # VPO + self.valve_states_enum[self.VALVE_BYPASS_FILTER] = VPiVSPVBfStates(self._binary_to_valve_state(vst[0] & 32)).name # VBF + self.valve_states_enum[self.VALVE_RECIRCULATE] = VDrVRcStates(self._binary_to_valve_state(vst[0] & 64)).name # VRC + self.valve_states_enum[self.VALVE_DRAIN] = VDrVRcStates(self._binary_to_valve_state(vst[0] & 128)).name # VDR + self.valve_states_enum[self.VALVE_PRESSURE_INLET] = VPiVSPVBfStates(self._binary_to_valve_state(vst[0] & 256)).name # VPI + self.valve_states_enum[self.VALVE_SAMPLING_PORT] = VPiVSPVBfStates(self._binary_to_valve_state(vst[0] & 512)).name # VSP + self.valve_states_enum[self.VALVE_RESERVOIR_1] = self._binary_to_valve_state(vst[0] & 1024) # VR1 + self.valve_states_enum[self.VALVE_RESERVOIR_2] = self._binary_to_valve_state(vst[0] & 2048) # VR2 + self.valve_states_enum[self.VALVE_PRODUCTION_DRAIN] = VPdStates(self._binary_to_valve_state(vst[0] & 4096)).name # VPD + def cmd_valve_override(self, state, valve, reset=NO_RESET): """ Constructs and sends the valve state override command. Index: tests/dg_heat_disinfect_test.py =================================================================== diff -u --- tests/dg_heat_disinfect_test.py (revision 0) +++ tests/dg_heat_disinfect_test.py (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -0,0 +1,88 @@ + + +import sys +sys.path.append("..") +from dialin.dg.dialysate_generator import DG +from dialin.dg.heat_disinfection import HeatDisinfectionStates +from dialin.dg.heat_disinfection import HeatDisinfectionInternalStates +from dialin.dg.drain_pump import DrainPumpStates +from dialin.dg.thermistors import Thermistors +from dialin.dg.uv_reactors import UVReactors +from dialin.dg.uv_reactors import ReactorsStates +from time import sleep + + +if __name__ == "__main__": + + dg = DG(log_level='DEBUG') + dg.cmd_log_in_to_dg() + + dg.uv_reactors.cmd_start_stop_inlet_uv_reactor(state=ReactorsStates.UV_REACTOR_STATE_ON.name) + + while True: + sleep(1) + print(dg.thermistors.onboard_temperature) + + f = open("Heat_disinfection.txt", "w") + + #dg.drain_pump.cmd_drain_pump_speed_set_point_override(2800) + + #dg.valves.cmd_valve_override(0, dg.valves.VALVE_PRESSURE_OUTLET ) + #sleep(1) + #dg.valves.cmd_valve_override(0, dg.valves.VALVE_RESERVOIR_OUTLET) + #dg.valves.cmd_valve_override(1, dg.valves.VALVE_RESERVOIR_INLET) + dg.heat_disinfect.cmd_start_stop_heat_disinfection(start=False) + sleep(1) + time = 1 + + dg.heat_disinfect.cmd_start_stop_heat_disinfection() + + try: + while True: + """ + var = ('Mode, {}, State, {}, Sub, {}, RO, {}, Drain, {}, VPi, {}, VBf, {}, VSP, {}, VPd, {}, VPo, {}, VDr, {}, ' + 'VRc, {}, VRo, {}, VRd, {}, VRi, {}, VRf, {}\r' + .format(dg.dg_operation_mode, + HeatDisinfectionStates(dg.dg_operation_sub_mode).name, + HeatDisinfectionInternalStates(dg.heat_disinfect.internal_state).name, + dg.ro_pump.ro_pump_state, + DrainPumpStates(dg.drain_pump.drain_pump_state).name, + dg.valves.valve_states_enum[dg.valves.VALVE_PRESSURE_INLET], + dg.valves.valve_states_enum[dg.valves.VALVE_BYPASS_FILTER], + dg.valves.valve_states_enum[dg.valves.VALVE_SAMPLING_PORT], + dg.valves.valve_states_enum[dg.valves.VALVE_PRODUCTION_DRAIN], + dg.valves.valve_states_enum[dg.valves.VALVE_PRESSURE_OUTLET], + dg.valves.valve_states_enum[dg.valves.VALVE_DRAIN], + dg.valves.valve_states_enum[dg.valves.VALVE_RECIRCULATE], + dg.valves.valve_states_enum[dg.valves.VALVE_RESERVOIR_OUTLET], + dg.valves.valve_states_enum[dg.valves.VALVE_RESERVOIR_DRAIN], + dg.valves.valve_states_enum[dg.valves.VALVE_RESERVOIR_INLET], + dg.valves.valve_states_enum[dg.valves.VALVE_RESERVOIR_FILL])) + """ + var = ('Mode, {}, State, {}, Sub, {}, RO, {}, Flow, {:5.3f}, TgtPres, {:5.3f}, InletPres, {:5.3f}, ' + 'OutletPres, {:5.3f}, PWM, {:5.3f}, Drain, {}, DInletPres, {:5.3f}, DOutletPres, {:5.3f}, ' + 'DrainDAC, {:5.3f}, R1, {:5.3f}, R2, {:5.3f}, TPi, {:5.3f}, TPo, {:5.3f}, TDi, {:5.3f} \r' + .format(dg.dg_operation_mode, + HeatDisinfectionStates(dg.dg_operation_sub_mode).name, + HeatDisinfectionInternalStates(dg.heat_disinfect.internal_state).name, + dg.ro_pump.ro_pump_state, + dg.ro_pump.measured_flow_rate_lpm, + dg.ro_pump.target_pressure_psi, + dg.pressures.ro_pump_inlet_pressure, + dg.pressures.ro_pump_outlet_pressure, + dg.ro_pump.pwm_duty_cycle_pct, + DrainPumpStates(dg.drain_pump.drain_pump_state).name, + dg.pressures.drain_pump_inlet_pressure, + dg.pressures.drain_pump_outlet_pressure, dg.drain_pump.dac_value, + dg.load_cells.load_cell_A1, + dg.load_cells.load_cell_B1, + dg.temperature_sensors.inlet_primary, dg.temperature_sensors.outlet_primary, + dg.temperature_sensors.outlet_redundancy)) + + print(var) + f.write(var) + sleep(0.25) + + except KeyboardInterrupt: + dg.heat_disinfect.cmd_start_stop_heat_disinfection(start=False) + f.close() Fisheye: Tag 6b7fe9b82f599b521d8e5d53922bc59841acd899 refers to a dead (removed) revision in file `tests/dg_heatdisinfect.py'. Fisheye: No comparison available. Pass `N' to diff? Index: tests/test_uf.py =================================================================== diff -u -rfdac759dbbec54375d4b3ebb21aebcc684ac1aed -r6b7fe9b82f599b521d8e5d53922bc59841acd899 --- tests/test_uf.py (.../test_uf.py) (revision fdac759dbbec54375d4b3ebb21aebcc684ac1aed) +++ tests/test_uf.py (.../test_uf.py) (revision 6b7fe9b82f599b521d8e5d53922bc59841acd899) @@ -57,7 +57,7 @@ pumpSetPts = ", B.s, " + '{:4d}'.format(hd.bloodflow.target_blood_flow_rate) + \ ", DI.s, " + '{:4d}'.format(hd.dialysate_inlet_flow.target_dialysate_inlet_flow_rate) + \ ", RO.s, " + '{:4d}'.format(dg.ro_pump.target_pressure_psi) + \ - ", DR.s, " + '{:5d}'.format(dg.drain_pump.target_drain_pump_speed_RPM) + ", DR.s, " + '{:5d}'.format(dg.drain_pump.target_drain_pump_RPM) pumpMeasSpds = ", B.m, " + '{:7.1f}'.format(hd.bloodflow.measured_blood_pump_speed) + \ ", B.r, " + '{:6.1f}'.format(hd.bloodflow.measured_blood_pump_rotor_speed) + \ ", B.f, " + '{:7.1f}'.format(hd.bloodflow.measured_blood_flow_rate) + \