Index: dialin/common/msg_defs.py =================================================================== diff -u -rdd35c2e4427612ca17937e04f9f0043e294b827c -rd531ce09d0240e0ae542ea33cf8ebe4b8169825b --- dialin/common/msg_defs.py (.../msg_defs.py) (revision dd35c2e4427612ca17937e04f9f0043e294b827c) +++ dialin/common/msg_defs.py (.../msg_defs.py) (revision d531ce09d0240e0ae542ea33cf8ebe4b8169825b) @@ -84,6 +84,7 @@ 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_USER_UF_PAUSE_RESUME_RESPONSE = 0x3F # HD response to user request to pause or resume UF + MSG_ID_DG_CONCENTRATE_PUMP_DATA = 0x42, # DG broadcast of concentrate pump data MSG_ID_CAN_ERROR_COUNT = 0x999 # test code in support of EMC testing @@ -185,7 +186,10 @@ MSG_ID_HEAT_DISINFECT_PUBLISH_INTERVAL_OVERRIDE = 0xA021 # Heat disinfection data publish interval override request MSG_ID_PRIMING_STATUS = 0x0037 # The priming status MSG_ID_DG_SOFTWARE_RESET_REQUEST = 0xA022 # DG reset request - MSG_ID_HD_VALVES_SET_BLOOD_TRAP_VALVE = 0x8030 # HD valves set blood trap valve state + MSG_ID_DG_OPERATION_MODE_REQUEST = 0xA023 # DG change operation mode request + MSG_ID_CONCENTRATE_PUMP_TARGET_SPEED_OVERRIDE = 0xA024 # Concentrate pump target speed override request + MSG_ID_CONCENTRATE_PUMP_STATE_CHANGE_REQUEST = 0xA026 # Concentrate pump state change request + 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/concentrate_pumps.py =================================================================== diff -u --- dialin/dg/concentrate_pumps.py (revision 0) +++ dialin/dg/concentrate_pumps.py (revision d531ce09d0240e0ae542ea33cf8ebe4b8169825b) @@ -0,0 +1,165 @@ +########################################################################### +# +# 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 concentrate_pumps.py +# +# @author (last) Quang Nguyen +# @date (last) 29-Oct-2020 +# @author (original) Quang Nguyen +# @date (original) 29-Oct-2020 +# +############################################################################ +import struct +from .constants import RESET,NO_RESET +from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from ..protocols.CAN import (DenaliMessage, DenaliChannels) +from ..utils.base import _AbstractSubSystem, _publish +from ..common.msg_defs import MsgIds +from logging import Logger + + +class ConcentratePumps(_AbstractSubSystem): + """ + ConcentratePumps + + Dialysate Generator (DG) Dialin API sub-class for concentrate pumps related commands. + """ + + # Conductivity sensor broadcast message field positions + START_POS_CP1_TARGET = DenaliMessage.PAYLOAD_START_INDEX + END_POS_CP1_TARGET = START_POS_CP1_TARGET + 4 + START_POS_CP1 = END_POS_CP1_TARGET + END_POS_CP1 = START_POS_CP1 + 4 + START_POS_CP2_TARGET = END_POS_CP1 + END_POS_CP2_TARGET = START_POS_CP2_TARGET + 4 + START_POS_CP2 = END_POS_CP2_TARGET + END_POS_CP2 = START_POS_CP2 + 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_CONCENTRATE_PUMP_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_concentrate_pumps_sync) + + self.concentrate_pump_cp1_target = 0.0 + self.concentrate_pump_cp1 = 0.0 + self.concentrate_pump_cp2_target = 0.0 + self.concentrate_pump_cp2 = 0.0 + + def get_concentrate_pumps(self): + """ + Gets the current concentrate pump data value + + @return: List containing concentrate pump data values: + [ concentrate_pump_cp1_target, concentrate_pump_cp1, concentrate_pump_cp2_target, concentrate_pump_cp2 ] + """ + return [self.concentrate_pump_cp1_target, self.concentrate_pump_cp1, self.concentrate_pump_cp2_target, self.concentrate_pump_cp2] + + @_publish(["concentrate_pump_cp1_target", "concentrate_pump_cp1", "concentrate_pump_cp2_target", "concentrate_pump_cp2"]) + def _handler_concentrate_pumps_sync(self, message): + """ + Handles published concentrate pumps' data messages. Concentrate pumps' speed data are captured + for reference. + + @param message: published concentrate pumps' data message + @return: None + """ + + cp1_target = struct.unpack('f', bytearray(message['message'][self.START_POS_CP1_TARGET:self.END_POS_CP1_TARGET])) + cp1 = struct.unpack('f', bytearray(message['message'][self.START_POS_CP1:self.END_POS_CP1])) + cp2_target = struct.unpack('f', bytearray(message['message'][self.START_POS_CP2_TARGET:self.END_POS_CP2_TARGET])) + cp2 = struct.unpack('f', bytearray(message['message'][self.START_POS_CP2:self.END_POS_CP2])) + + self.concentrate_pump_cp1_target = cp1_target[0] + self.concentrate_pump_cp1 = cp1[0] + self.concentrate_pump_cp2_target = cp2_target[0] + self.concentrate_pump_cp2 = cp2[0] + + def cmd_concentrate_pump_on_request(self): + payload = integer_to_bytearray(1) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_CONCENTRATE_PUMP_STATE_CHANGE_REQUEST.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + self.logger.debug("Requested to turn concentrate pumps on!") + + # 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.error("Timeout!!!!") + return False + + + def cmd_concentrate_pump_off_request(self): + payload = integer_to_bytearray(0) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_CONCENTRATE_PUMP_STATE_CHANGE_REQUEST.value, + payload=payload) + # Send message + received_message = self.can_interface.send(message) + self.logger.debug("Requested to turn concentrate pumps off") + + # 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.error("Timeout!!!!") + return False + + def cmd_concentrate_pump_target_speed_override(self, speed, pump_id, reset=NO_RESET): + """ + Constructs and sends the concentrate pump target speed override command + + @param speed: float - target speed value to override concentrate pump with + @param pump_id: unsigned int - concentrate pump ID + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + + Concentrate pump IDs: \n + 0 = CP1 \n + 1 = CP2 \n + """ + + reset_byte_array = integer_to_bytearray(reset) + speed_byte_array = float_to_bytearray(speed) + pump_id_byte_array = integer_to_bytearray(pump_id) + payload = reset_byte_array + speed_byte_array + pump_id_byte_array + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_CONCENTRATE_PUMP_TARGET_SPEED_OVERRIDE.value, + payload=payload) + + if reset == RESET: + self.logger.debug("reset back to normal value for ID: " + str(pump_id)) + else: + self.logger.debug("override value: " + str(speed) + " - for ID: " + str(pump_id)) + + # 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.error("Timeout!!!!") + return False + Index: dialin/dg/conductivity_sensors.py =================================================================== diff -u -rcd9d98248537d10d9cf188307ae2237c8cf8e6e4 -rd531ce09d0240e0ae542ea33cf8ebe4b8169825b --- dialin/dg/conductivity_sensors.py (.../conductivity_sensors.py) (revision cd9d98248537d10d9cf188307ae2237c8cf8e6e4) +++ dialin/dg/conductivity_sensors.py (.../conductivity_sensors.py) (revision d531ce09d0240e0ae542ea33cf8ebe4b8169825b) @@ -8,7 +8,7 @@ # @file conductivity_sensors.py # # @author (last) Quang Nguyen -# @date (last) 21-Aug-2020 +# @date (last) 29-Oct-2020 # @author (original) Quang Nguyen # @date (original) 20-Jul-2020 # @@ -48,14 +48,16 @@ self.ro_rejection_ratio = 0.0 self.conductivity_sensor_cpi = 0.0 self.conductivity_sensor_cpo = 0.0 + self.conductivity_sensor_cd1 = 0.0 + self.conductivity_sensor_cd2 = 0.0 def get_conductivity_sensors(self): """ Gets the current conductivity value - @return: List containing conductivity values: [ conductivity_sensor_cpi, conductivity_sensor_cpo ] + @return: List containing conductivity values: [ conductivity_sensor_cpi, conductivity_sensor_cpo, conductivity_sensor_cd1, conductivity_sensor_cd2 ] """ - return [self.conductivity_sensor_cpi, self.conductivity_sensor_cpo] + return [self.conductivity_sensor_cpi, self.conductivity_sensor_cpo, self.conductivity_sensor_cd1, self.conductivity_sensor_cd2] def get_RO_rejection_ratio(self): """ @@ -65,7 +67,7 @@ """ return self.ro_rejection_ratio - @_publish(["ro_rejection_ratio", "conductivity_sensor_cpi", "conductivity_sensor_cpo"]) + @_publish(["ro_rejection_ratio", "conductivity_sensor_cpi", "conductivity_sensor_cpo", "conductivity_sensor_cd1", "conductivity_sensor_cd2"]) def _handler_conductivity_sensors_sync(self, message): """ Handles published conductivity sensor data messages. Conductivity sensor data are captured @@ -78,10 +80,14 @@ ro_rejection_ratio = struct.unpack('f', bytearray(message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) cpi = struct.unpack('f', bytearray(message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) cpo = struct.unpack('f', bytearray(message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) + cd1 = struct.unpack('f', bytearray(message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) + cd2 = struct.unpack('f', bytearray(message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) self.ro_rejection_ratio = ro_rejection_ratio[0] self.conductivity_sensor_cpi = cpi[0] self.conductivity_sensor_cpo = cpo[0] + self.conductivity_sensor_cd1 = cd1[0] + self.conductivity_sensor_cd2 = cd2[0] def cmd_conductivity_sensor_override(self, conductivity, sensor, reset=NO_RESET): """ Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rcd9d98248537d10d9cf188307ae2237c8cf8e6e4 -rd531ce09d0240e0ae542ea33cf8ebe4b8169825b --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision cd9d98248537d10d9cf188307ae2237c8cf8e6e4) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision d531ce09d0240e0ae542ea33cf8ebe4b8169825b) @@ -26,6 +26,7 @@ from .heaters import Heaters from .temperature_sensors import TemperatureSensors from .conductivity_sensors import ConductivitySensors +from .concentrate_pumps import ConcentratePumps from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish, _LogManager from ..common.msg_defs import MsgIds, MsgFldPositions @@ -136,6 +137,7 @@ self.heaters = Heaters(self.can_interface, self.logger) self.temperature_sensors = TemperatureSensors(self.can_interface, self.logger) self.conductivity_sensors = ConductivitySensors(self.can_interface, self.logger) + self.concentrate_pumps = ConcentratePumps(self.can_interface, self.logger) self.alarms = DGAlarms(self.can_interface, self.logger) def get_version(self): Index: dialin/hd/valves.py =================================================================== diff -u -r3f640809b83e8f5bc080ba3736d6c0719d1503df -rd531ce09d0240e0ae542ea33cf8ebe4b8169825b --- dialin/hd/valves.py (.../valves.py) (revision 3f640809b83e8f5bc080ba3736d6c0719d1503df) +++ dialin/hd/valves.py (.../valves.py) (revision d531ce09d0240e0ae542ea33cf8ebe4b8169825b) @@ -248,7 +248,7 @@ payload = integer_to_bytearray(0) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=MsgIds.MSG_ID_HD_VALVES_SET_BLOOD_TRAP_VALVE.value, + message_id=MsgIds.MSG_ID_HD_VALVES_SET_AIR_TRAP_VALVE.value, payload=payload) # Send message received_message = self.can_interface.send(message)