Index: dialin/dg/__init__.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -r2321d0094015467e41016c88f49f30cce3b25150 --- dialin/dg/__init__.py (.../__init__.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ dialin/dg/__init__.py (.../__init__.py) (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -22,5 +22,5 @@ from .pressures import DGPressures from .reservoirs import DGReservoirs from .ro_pump import DGROPump -from .temperature_sensors import TemperatureSensors +from .temperatures import TemperatureSensors from .valves import DGValves Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -r5400dea744738a3fed51b246038c93ebffcd914a -r2321d0094015467e41016c88f49f30cce3b25150 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 5400dea744738a3fed51b246038c93ebffcd914a) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -41,7 +41,7 @@ from .service_record import DGServiceNVRecord from .switches import DGSwitches from .system_record import DGSystemNVRecord -from .temperature_sensors import TemperatureSensors +from .temperatures import TemperatureSensors from .thermistors import Thermistors from .uv_reactors import UVReactors from .valves import DGValves Fisheye: Tag 2321d0094015467e41016c88f49f30cce3b25150 refers to a dead (removed) revision in file `dialin/dg/temperature_sensors.py'. Fisheye: No comparison available. Pass `N' to diff? Index: dialin/dg/temperatures.py =================================================================== diff -u --- dialin/dg/temperatures.py (revision 0) +++ dialin/dg/temperatures.py (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -0,0 +1,294 @@ +########################################################################### +# +# Copyright (c) 2019-2021 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 temperatures.py +# +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 02-Jun-2020 +# +############################################################################ +import struct +from enum import unique +from logging import Logger + +from .constants import NO_RESET +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray, float_to_bytearray + + +@unique +class DGTemperaturesNames(DialinEnum): + INLET_PRIMARY_HEATER = 0 + OUTLET_PRIMARY_HEATER = 1 + CONDUCTIVITY_SENSOR_1 = 2 + CONDUCTIVITY_SENSOR_2 = 3 + OUTLET_DIALYSATE_REDUNDANT = 4 + INLET_DIALYSATE = 5 + PRIMARY_HEATER_THERMOCOUPLE = 6 + TRIMMER_HEATER_THERMOCOUPLE = 7 + PRIMARY_HEATER_COLD_JUNCTION = 8 + TRIMMER_HEATER_COLD_JUNCTION = 9 + PRIMARY_HEATER_INTERNAL = 10 + TRIMMER_HEATER_INTERNAL = 11 + FPGA_BOARD_SENSOR = 12 + LOAD_CELL_A1_B1 = 13 + LOAD_CELL_A2_B2 = 14 + INTERNAL_THDO_RTD = 15 + INTERNAL_TDI_RTD = 16 + INTERNAL_COND_TEMP_SENSOR = 17 + + +class TemperatureSensors(AbstractSubSystem): + + def __init__(self, can_interface, logger: Logger): + + super().__init__() + + self.can_interface = can_interface + self.logger = logger + # Dictionary of the temperature sensors + self.temperature_sensors = {DGTemperaturesNames.INLET_PRIMARY_HEATER.name: {}, + DGTemperaturesNames.OUTLET_PRIMARY_HEATER.name: {}, + DGTemperaturesNames.CONDUCTIVITY_SENSOR_1.name: {}, + DGTemperaturesNames.CONDUCTIVITY_SENSOR_2.name: {}, + DGTemperaturesNames.OUTLET_DIALYSATE_REDUNDANT.name: {}, + DGTemperaturesNames.INLET_DIALYSATE.name: {}, + DGTemperaturesNames.PRIMARY_HEATER_THERMOCOUPLE.name: {}, + DGTemperaturesNames.TRIMMER_HEATER_THERMOCOUPLE.name: {}, + DGTemperaturesNames.PRIMARY_HEATER_COLD_JUNCTION.name: {}, + DGTemperaturesNames.TRIMMER_HEATER_COLD_JUNCTION.name: {}, + DGTemperaturesNames.PRIMARY_HEATER_INTERNAL.name: {}, + DGTemperaturesNames.TRIMMER_HEATER_INTERNAL.name: {}, + DGTemperaturesNames.FPGA_BOARD_SENSOR.name: {}, + DGTemperaturesNames.LOAD_CELL_A1_B1.name: {}, + DGTemperaturesNames.LOAD_CELL_A2_B2.name: {}, + DGTemperaturesNames.INTERNAL_THDO_RTD.name: {}, + DGTemperaturesNames.INTERNAL_TDI_RTD.name: {}, + DGTemperaturesNames.INTERNAL_COND_TEMP_SENSOR.name: {}} + + self.primary_raw_thermo_couple = 0 + self.primary_raw_cold_junc = 0 + self.trimmer_raw_thermo_couple = 0 + self.trimmer_raw_cold_junc = 0 + self.conductivity_1_raw = 0 + self.conductivity_2_raw = 0 + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_DG_TEMPERATURE_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_temperature_sensors_sync) + + def get_temperature(self, sensor): + """ + Gets a temperature sensor's value + + @param sensor: (str) Name of the sensor e.g. TemperatureSensorsNames.INLET_PRIMARY_HEATER.name + @return: The temperature of a temperature sensor + """ + return self.temperature_sensors[sensor] + + @publish(["temperature_sensors", "primary_raw_thermo_couple", "primary_raw_cold_junc", + "trimmer_raw_thermo_couple", "trimmer_raw_cold_junc", "conductivity_1_raw", "conductivity_2_raw"]) + def _handler_temperature_sensors_sync(self, message): + """ + Handles published temperature sensors message + + @param message: published temperature sensors data message + @returns none + """ + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.temperature_sensors[DGTemperaturesNames.INLET_PRIMARY_HEATER.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.temperature_sensors[DGTemperaturesNames.OUTLET_PRIMARY_HEATER.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + self.temperature_sensors[DGTemperaturesNames.CONDUCTIVITY_SENSOR_1.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + self.temperature_sensors[DGTemperaturesNames.CONDUCTIVITY_SENSOR_2.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + self.temperature_sensors[DGTemperaturesNames.OUTLET_DIALYSATE_REDUNDANT.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + self.temperature_sensors[DGTemperaturesNames.INLET_DIALYSATE.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] + self.temperature_sensors[DGTemperaturesNames.PRIMARY_HEATER_THERMOCOUPLE.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] + self.temperature_sensors[DGTemperaturesNames.TRIMMER_HEATER_THERMOCOUPLE.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] + self.temperature_sensors[DGTemperaturesNames.PRIMARY_HEATER_COLD_JUNCTION.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10]))[0] + self.temperature_sensors[DGTemperaturesNames.TRIMMER_HEATER_COLD_JUNCTION.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11]))[0] + self.temperature_sensors[DGTemperaturesNames.PRIMARY_HEATER_INTERNAL.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12]))[0] + self.temperature_sensors[DGTemperaturesNames.TRIMMER_HEATER_INTERNAL.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_13:MsgFieldPositions.END_POS_FIELD_13]))[0] + self.temperature_sensors[DGTemperaturesNames.FPGA_BOARD_SENSOR.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_14:MsgFieldPositions.END_POS_FIELD_14]))[0] + self.temperature_sensors[DGTemperaturesNames.LOAD_CELL_A1_B1.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_15:MsgFieldPositions.END_POS_FIELD_15]))[0] + self.temperature_sensors[DGTemperaturesNames.LOAD_CELL_A2_B2.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_16:MsgFieldPositions.END_POS_FIELD_16]))[0] + self.temperature_sensors[DGTemperaturesNames.INTERNAL_THDO_RTD.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_17:MsgFieldPositions.END_POS_FIELD_17]))[0] + self.temperature_sensors[DGTemperaturesNames.INTERNAL_TDI_RTD.name] = sensors_data + + sensors_data = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_18:MsgFieldPositions.END_POS_FIELD_18]))[0] + self.temperature_sensors[DGTemperaturesNames.INTERNAL_COND_TEMP_SENSOR.name] = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_19:MsgFieldPositions.END_POS_FIELD_19]))[0] + self.primary_raw_thermo_couple = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_20:MsgFieldPositions.END_POS_FIELD_20]))[0] + self.primary_raw_cold_junc = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_21:MsgFieldPositions.END_POS_FIELD_21]))[0] + self.trimmer_raw_thermo_couple = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_22:MsgFieldPositions.END_POS_FIELD_22]))[0] + self.trimmer_raw_cold_junc = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_23:MsgFieldPositions.END_POS_FIELD_23]))[0] + self.conductivity_1_raw = sensors_data + + sensors_data = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_24:MsgFieldPositions.END_POS_FIELD_24]))[0] + self.conductivity_2_raw = sensors_data + + def cmd_temperatures_data_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends broadcast time interval. + 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) Publish time interval in ms + @param reset: (int) 1 to reset a previous override, 0 to override + @returns 1 if successful, zero otherwise + """ + if not check_broadcast_interval_override_ms(ms): + return False + + reset_value = integer_to_bytearray(reset) + interval_value = integer_to_bytearray(ms) + payload = reset_value + interval_value + + message = DenaliMessage.build_message( + channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("Sending {} ms publish interval to the Temperature Sensors module".format(ms)) + # Send message + received_message = self.can_interface.send(message) + + # If there is content in message + if received_message is not None: + # Response payload is OK or not + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + + def cmd_temperatures_value_override(self, sensor_index: int, + sensor_value: float, reset: int = NO_RESET) -> int: + """ + Constructs and sends the value override of a temperature sensor. + Constraints: + Must be logged into DG. + Given sensor_index must be one of the sensors listed below. + + @param sensor_index : (int) Index of the sensor + @param sensor_value: (float) Value of the sensor to override + @param reset: (int) whether to reset the override value. The default is NO_RESET + @returns 1 if successful, zero otherwise + + @details temperature sensor indexes: \n + 0 = Primary Heater Inlet + 1 = Primary Heater Outlet + 2 = Conductivity Sensor 1 + 3 = Conductivity Sensor 2 + 4 = Dialysate (Redundant) + 5 = Dialysate + 6 = Primary Heater Thermocouple + 7 = Trimmer Heater Thermocouple + 8 = Primary Heater Cold Junction + 9 = Trimmer Heater Cold Junction + 10= Primary Heater Internal + 11= Trimmer Heater Internal + 12= FPGA board + 13= Load cell A1/B1 + 14= Load cell A2/B2 + 15= Internal THDO RTD + 16= Internal TDI RTD + 17= Internal conductivity temp sensor + """ + rst = integer_to_bytearray(reset) + value = float_to_bytearray(sensor_value) + index = integer_to_bytearray(sensor_index) + + payload = rst + value + index + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE.value, + payload=payload) + + self.logger.debug("Setting sensor {} to {} C".format(sensor_index, sensor_value)) + + # Send message + received_message = self.can_interface.send(message) + + # If there is content in message + if received_message is not None: + # Response payload is OK or not + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False Index: tests/dg_heat_and_chemical_disinfect_test.py =================================================================== diff -u -r6e974c56c900d789bd690a5f5e8b6698f0aaed2c -r2321d0094015467e41016c88f49f30cce3b25150 --- tests/dg_heat_and_chemical_disinfect_test.py (.../dg_heat_and_chemical_disinfect_test.py) (revision 6e974c56c900d789bd690a5f5e8b6698f0aaed2c) +++ tests/dg_heat_and_chemical_disinfect_test.py (.../dg_heat_and_chemical_disinfect_test.py) (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -23,7 +23,7 @@ from dialin.dg.chemical_disinfect import ChemCancellationModes from dialin.dg.drain_pump import DrainPumpStates from dialin.dg.thermistors import ThermistorsNames -from dialin.dg.temperature_sensors import DGTemperaturesNames +from dialin.dg.temperatures import DGTemperaturesNames from dialin.dg.dialysate_generator import DGOperationModes from dialin.hd.temperatures import HDTemperaturesNames from dialin.common.hd_defs import HDOpModes, HDOpSubModes Index: tests/test_uf.py =================================================================== diff -u -r6e974c56c900d789bd690a5f5e8b6698f0aaed2c -r2321d0094015467e41016c88f49f30cce3b25150 --- tests/test_uf.py (.../test_uf.py) (revision 6e974c56c900d789bd690a5f5e8b6698f0aaed2c) +++ tests/test_uf.py (.../test_uf.py) (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -18,7 +18,7 @@ sys.path.append("..") from dialin.hd.hemodialysis_device import HD from dialin.dg.dialysate_generator import DG -from dialin.dg.temperature_sensors import DGTemperaturesNames +from dialin.dg.temperatures import DGTemperaturesNames from time import sleep if __name__ == "__main__": Index: tests/unit_tests/test_dg_temperature_sensors.py =================================================================== diff -u -r6e974c56c900d789bd690a5f5e8b6698f0aaed2c -r2321d0094015467e41016c88f49f30cce3b25150 --- tests/unit_tests/test_dg_temperature_sensors.py (.../test_dg_temperature_sensors.py) (revision 6e974c56c900d789bd690a5f5e8b6698f0aaed2c) +++ tests/unit_tests/test_dg_temperature_sensors.py (.../test_dg_temperature_sensors.py) (revision 2321d0094015467e41016c88f49f30cce3b25150) @@ -21,7 +21,7 @@ class DGTemperatureSensors(unittest.TestCase): def test_temperature_sensors(self): - from dialin.dg.temperature_sensors import DGTemperaturesNames + from dialin.dg.temperatures import DGTemperaturesNames i = 0 for e in DGTemperaturesNames: