Index: dialin/common/msg_ids.py =================================================================== diff -u -r19d246d9c099e1a15570767f82ca79502aff2776 -r79334f431b2177aa87bded7e28872e293cea8f05 --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 19d246d9c099e1a15570767f82ca79502aff2776) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision 79334f431b2177aa87bded7e28872e293cea8f05) @@ -389,7 +389,7 @@ MSG_ID_DG_THERMISTORS_DATA_PUBLISH_INTERVAL_OVERRIDE = 0xA02D MSG_ID_DG_THERMISTORS_VALUE_OVERRIDE = 0xA02E MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE = 0xA02F - MSG_ID____AVAILABLE_5 = 0xA030 + MSG_ID_DG_VALVES_SENSED_STATE_OVERRIDE = 0xA030 MSG_ID_DG_SET_RO_PUMP_TARGET_FLOW = 0xA031 MSG_ID_DG_RO_PUMP_TARGET_PRESSURE_OVERRIDE = 0xA032 MSG_ID_DG_SET_CALIBRATION_RECORD = 0xA033 @@ -429,6 +429,8 @@ MSG_ID_DG_SEND_USAGE_INFO_RECORD = 0xA055 MSG_ID_DG_SET_OP_MODE_REQUEST = 0xA056 MSG_ID_DG_RESERVOIR_TARE_REQUEST = 0xA057 + MSG_ID_DG_DRAIN_PUMP_CURRENT_OVERRIDE = 0xA058 + MSG_ID_DG_DRAIN_PUMP_DIRECTION_OVERRIDE = 0xA059 MSG_ID_HD_DEBUG_EVENT = 0xFFF1 MSG_ID_DG_DEBUG_EVENT = 0xFFF2 Index: dialin/dg/drain_pump.py =================================================================== diff -u -rbff28676dd855ea33707bbb26a624abc94aebdf0 -r79334f431b2177aa87bded7e28872e293cea8f05 --- dialin/dg/drain_pump.py (.../drain_pump.py) (revision bff28676dd855ea33707bbb26a624abc94aebdf0) +++ dialin/dg/drain_pump.py (.../drain_pump.py) (revision 79334f431b2177aa87bded7e28872e293cea8f05) @@ -267,3 +267,82 @@ else: self.logger.debug("Timeout!!!!") return False + + def cmd_drain_pump_measured_current_amps_override(self, current: float, reset: int = NO_RESET) -> int: + """ + Constructs and sends the drain pump measured current override command. + Constraints: + Must be logged into DG. + + @param current: (float) current to override with + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + rst = integer_to_bytearray(reset) + r = float_to_bytearray(current) + payload = rst + r + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_DRAIN_PUMP_CURRENT_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override drain pump measured current") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal" + else: + str_res = str(current) + self.logger.debug( + "Drain pump measured current overridden to " + str_res + " A " + + 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_drain_pump_measured_direction_override(self, direction: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the drain pump measured direction override command. + Constraints: + Must be logged into DG. + 1 will be forward and 0 will be backwards + + @param direction: (int) direction to override with + @param reset: (int) 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + rst = integer_to_bytearray(reset) + r = integer_to_bytearray(direction) + payload = rst + r + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_DRAIN_PUMP_DIRECTION_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override drain pump measured direction") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal" + else: + str_res = str(direction) + self.logger.debug( + "Drain pump measured direction 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: + self.logger.debug("Timeout!!!!") + return False Index: dialin/dg/valves.py =================================================================== diff -u -r3a70bfb451b74106348c064c34f19934aadd9119 -r79334f431b2177aa87bded7e28872e293cea8f05 --- dialin/dg/valves.py (.../valves.py) (revision 3a70bfb451b74106348c064c34f19934aadd9119) +++ dialin/dg/valves.py (.../valves.py) (revision 79334f431b2177aa87bded7e28872e293cea8f05) @@ -17,6 +17,7 @@ import struct from enum import unique from logging import Logger +from collections import OrderedDict from .constants import NO_RESET from ..common.msg_defs import MsgIds @@ -66,9 +67,29 @@ VALVE_STATE_R1_C_TO_NC = 1 +@unique +class DGValveNames(DialinEnum): + # NOTE: NUM_OF enum has been removed because it should be a part of the software configuration + # structure since the members of this class is for looped to create the dictionary automatically + VALVE_RESERVOIR_FILL = 0 # VRF + VALVE_RESERVOIR_INLET = 1 # VRI + RESERVED_SPACE = 2 # RESERVED SPACE + VALVE_RESERVOIR_OUTLET = 3 # VRO + VALVE_PRESSURE_OUTLET = 4 # VPO + VALVE_BYPASS_FILTER = 5 # VBF + VALVE_RECIRCULATE = 6 # VRC + VALVE_DRAIN = 7 # VDR + VALVE_PRESSURE_INLET = 8 # VPI + VALVE_SAMPLING_PORT = 9 # VSP + VALVE_RESERVOIR_DRAIN_1 = 10 # VRD1 + VALVE_RESERVOIR_DRAIN_2 = 11 # VRD2 + VALVE_PRODUCTION_DRAIN = 12 # VPD + + class DGValves(AbstractSubSystem): """ Dialysate Generation (DG) interface for valve related commands. + """ # Valves states publish message field positions @@ -100,6 +121,7 @@ super().__init__() self.can_interface = can_interface self.logger = logger + self.valves_sensed_states = OrderedDict() if self.can_interface is not None: channel_id = DenaliChannels.dg_sync_broadcast_ch_id @@ -123,6 +145,9 @@ self.valve_states_enum = [0 for _ in range(self.NUM_OF_VALVES)] + for valve in DGValveNames.__members__: + self.valves_sensed_states[valve] = 0 + def get_valve_states(self): """ Gets the valve states @@ -280,6 +305,65 @@ self.valve_states_enum[self.VALVE_RESERVOIR_DRAIN_2] = VPiVSPVBfVRD1VRD2States(self._binary_to_valve_state(vst[0] & 2048)).name # VRD2 self.valve_states_enum[self.VALVE_PRODUCTION_DRAIN] = VPdStates(self._binary_to_valve_state(vst[0] & 4096)).name # VPD + # TODO Yes Behrouz, I will switch to the new method with automation scripts! No not immediately Behrouz. + # Dude this is an improvement hold on, it won't be ready immediately + start = 3 + end = start + 1 + for valve_id in self.valves_sensed_states: + self.valves_sensed_states[valve_id] = struct.unpack('B', bytearray(message['message'][start:end]))[0] + start = end + end += 1 + + def cmd_valve_sensed_state_override(self, valve: int, state: bool, reset: int = NO_RESET) -> int: + """ + Constructs and sends the valve sensed state override command. + Constraints: + Must be logged into DG. + Given valve ID must be one of the valve IDs listed below. + + @param valve: unsigned int - valve ID + @param state: bool - valve state + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + + valve IDs: \n + 0 = Valve Reservoir Fill \n + 1 = Valve Reservoir Inlet \n + 2 = Valve Reservoir Drain \n + 3 = Valve Reservoir Outlet \n + 4 = Valve Pressure Outlet \n + 5 = Valve Bypass Filter \n + 6 = Valve Recirculate \n + 7 = Valve Drain \n + 8 = Valve Pressure Inlet \n + 9 = Valve Sampling Port \n + 10 = Valve Reservoir 1 Drain \n + 11 = Valve Reservoir 2 Drain \n + 12 = Valve Production Drain \n + """ + + rst = integer_to_bytearray(reset) + ste = integer_to_bytearray(int(state)) + vlv = integer_to_bytearray(valve) + payload = rst + ste + vlv + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_VALVES_SENSED_STATE_OVERRIDE.value, + payload=payload) + + self.logger.debug("Override valve sensed state") + + # 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("Timeout!!!!") + return False + def cmd_valve_override(self, valve: int, state: bool, reset: int = NO_RESET) -> int: """ Constructs and sends the valve state override command. @@ -317,7 +401,7 @@ message_id=MsgIds.MSG_ID_VALVE_STATE_OVERRIDE.value, payload=payload) - self.logger.debug("override valve state") + self.logger.debug("Override valve state") # Send message received_message = self.can_interface.send(message) Index: dialin/hd/blood_leak.py =================================================================== diff -u -rbff28676dd855ea33707bbb26a624abc94aebdf0 -r79334f431b2177aa87bded7e28872e293cea8f05 --- dialin/hd/blood_leak.py (.../blood_leak.py) (revision bff28676dd855ea33707bbb26a624abc94aebdf0) +++ dialin/hd/blood_leak.py (.../blood_leak.py) (revision 79334f431b2177aa87bded7e28872e293cea8f05) @@ -176,8 +176,7 @@ return self.blood_leak_emb_mode_cmd_response - @publish(['blood_leak_status', 'blood_leak_state', 'blood_leak_detect_set_point', 'blood_leak_detect_level', - 'blood_leak_led_intensity']) + @publish(['blood_leak_status', 'blood_leak_state']) def _handler_blood_leak_sync(self, message): """ Handles published blood leak status messages. Blood leak status is captured @@ -190,12 +189,6 @@ message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] self.blood_leak_state = struct.unpack('i', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.blood_leak_detect_set_point = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.blood_leak_detect_level = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.blood_leak_led_intensity = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] def cmd_blood_leak_detector_override(self, detected, reset=NO_RESET): """ Index: tests/dg_tests.py =================================================================== diff -u -r19d246d9c099e1a15570767f82ca79502aff2776 -r79334f431b2177aa87bded7e28872e293cea8f05 --- tests/dg_tests.py (.../dg_tests.py) (revision 19d246d9c099e1a15570767f82ca79502aff2776) +++ tests/dg_tests.py (.../dg_tests.py) (revision 79334f431b2177aa87bded7e28872e293cea8f05) @@ -133,11 +133,6 @@ def get_dg_run_info(): - # info = ('DG_op_mode, {}, DG_sub_mode, {}, Op, {}, Sub, {}, '.format(DGOperationModes(dg.dg_operation_mode).name, - # dg.dg_operation_sub_mode, - # dg.events.get_dg_events(DGEventList(1).value, 3), - # dg.events.get_dg_events(DGEventList(2).value, 3))) - info = ('DG_op_mode, {}, DG_op_mode_num, {}, DG_sub_mode, {}, '.format(DGOperationModes(dg.dg_operation_mode).name, dg.dg_operation_mode, dg.dg_operation_sub_mode)) @@ -164,12 +159,13 @@ def get_drain_states_info(): - info = ('Drain, {}, DAC, {}, Tgt_RPM, {}, Curr_RPM, {}, PRd, {:5.3f}, PDr, {:5.3f}, Drain_curr_A, {:5.3f}, ' - 'Drain_dir, {}, ' + info = ('Drain, {}, DAC, {}, Tgt_RPM, {}, Curr_RPM, {}, PRd, {:5.3f}, PDr, {:5.3f}, Baro, {:5.3f}, ' + 'Drain_curr_A, {:5.3f}, Drain_dir, {}, ' .format(DrainPumpStates(dg.drain_pump.drain_pump_state).name, dg.drain_pump.dac_value, dg.drain_pump.target_drain_pump_rpm, dg.drain_pump.current_drain_pump_rpm, dg.pressures.drain_pump_inlet_pressure, dg.pressures.drain_pump_outlet_pressure, - dg.drain_pump.drain_pump_current_A, dg.drain_pump.drain_pump_direction)) + dg.pressures.barometric_pressure, dg.drain_pump.drain_pump_current_A, + dg.drain_pump.drain_pump_direction)) return info @@ -220,13 +216,15 @@ def get_temperature_sensors_info(): info = ('TPi, {:5.3f}, THd, {:5.3f}, TPo, {:5.3f}, TD1, {:5.3f}, TD2, {:5.3f}, TRo, {:5.3f}, TDi, {:5.3f}, ' + 'Baro_temp, {:5.3f}, ' .format(dg.temperatures.temperatures[DGTemperaturesNames.INLET_PRIMARY_HEATER.name], dg.temperatures.temperatures[DGTemperaturesNames.HEAT_DISINFECT.name], dg.temperatures.temperatures[DGTemperaturesNames.OUTLET_PRIMARY_HEATER.name], dg.temperatures.temperatures[DGTemperaturesNames.CONDUCTIVITY_SENSOR_1.name], dg.temperatures.temperatures[DGTemperaturesNames.CONDUCTIVITY_SENSOR_2.name], dg.temperatures.temperatures[DGTemperaturesNames.OUTLET_DIALYSATE_REDUNDANT.name], - dg.temperatures.temperatures[DGTemperaturesNames.INLET_DIALYSATE.name])) + dg.temperatures.temperatures[DGTemperaturesNames.INLET_DIALYSATE.name], + dg.temperatures.temperatures[DGTemperaturesNames.BARO_TEMP_SENSOR.name])) return info