Index: leahi_dialin/common/dd_defs.py =================================================================== diff -u -rb3e7a0b4009eb7a95bbd1cbdf9a20024b519a3d7 -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision b3e7a0b4009eb7a95bbd1cbdf9a20024b519a3d7) +++ leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -7,13 +7,18 @@ # # @file dd_defs.py # -# @author (last) Dara Navaei -# @date (last) 08-Feb-2024 +# @author (last) Zoltan Miskolci +# @date (last) 13-Jan-2026 # @author (original) Peter Lucia # @date (original) 22-Jun-2021 # ############################################################################ + from enum import unique +from aenum import extend_enum +from typing import TYPE_CHECKING + +from .global_vars import GlobalVariables, test_config_change from ..utils.base import DialinEnum @@ -376,4 +381,665 @@ MONITORED_LINE_FPGA_VCC_V = 5 # FPGA Vcc (3V) MONITORED_LINE_FPGA_AUX_V = 6 # FPGA Vaux (3V) MONITORED_LINE_FPGA_PVN_V = 7 # FPGA Vpvn (1V) - NUM_OF_MONITORED_VOLTAGE_LINES = 8 # Number of TD operation modes \ No newline at end of file + NUM_OF_MONITORED_VOLTAGE_LINES = 8 # Number of TD operation modes + +class DD_Defs: + + # IDE autocomplete support + if TYPE_CHECKING: + DDOpModes: DialinEnum + DDFaultStates: DialinEnum + DDFaultNVDataStates: DialinEnum + DDServiceStates: DialinEnum + DDInitStates: DialinEnum + DDStandbyStates: DialinEnum + DDPreGenDialysateStates: DialinEnum + DDGenDialysateModeStates: DialinEnum + DDPostGenDialysateStates: DialinEnum + DDHeatDisinfectStates: DialinEnum + DDHeaterCoolingStates: DialinEnum + DDROPermeateStates: DialinEnum + DDNotLegalStates: DialinEnum + DDEventList: DialinEnum + DDEventDataTypes: DialinEnum + + DDConcentratePumpNames:DialinEnum + DDConductivitySensorNames:DialinEnum + DDDialysatePumpNames:DialinEnum + DDHeaterNames:DialinEnum + DDLevelSensorNames:DialinEnum + DDPistonPumpNames:DialinEnum + DDPressureSensorNames:DialinEnum + DDTemperatureSensorNames: DialinEnum + DDValveNames: DialinEnum + DDMonitoredVoltages: DialinEnum + + DDBalancingChamberStates:DialinEnum + DDBalancingChamberSwitchStates:DialinEnum + DDBloodLeakStates:DialinEnum + DDConcentratePumpAttributes:DialinEnum + DDConcentratePumpStates:DialinEnum + DDDialysatePumpAttributes:DialinEnum + DDDialysatePumpsStates:DialinEnum + DDHeaterStartStop:DialinEnum + DDHeaterAttributes:DialinEnum + DDHeaterExecState:DialinEnum + DDPistonPumpAttributes:DialinEnum + DDValveStates: DialinEnum + + _properties = { + # Operation / State enums + 'DDOpModes': '_create_dd_operation_modes', + 'DDFaultStates': '_create_dd_fault_states', + 'DDFaultNVDataStates': '_create_dd_fault_nvdata_states', + 'DDServiceStates': '_create_dd_service_states', + 'DDInitStates': '_create_dd_init_states', + 'DDStandbyStates': '_create_dd_standby_states', + 'DDPreGenDialysateStates': '_create_dd_pregen_states', + 'DDGenDialysateModeStates': '_create_dd_gen_states', + 'DDPostGenDialysateStates': '_create_dd_postgen_states', + 'DDHeatDisinfectStates': '_create_dd_heat_disinfect_states', + 'DDHeaterCoolingStates': '_create_dd_heater_cooling_states', + 'DDROPermeateStates': '_create_dd_ro_permeate_states', + 'DDNotLegalStates': '_create_dd_not_legal_states', + + # Event enums + 'DDEventList': '_create_dd_event_list', + 'DDEventDataTypes': '_create_dd_event_data_types', + + # Module Names enums + 'DDConcentratePumpNames': '_create_dd_concentrate_pump_names', + 'DDConductivitySensorNames': '_create_dd_conductivity_sensor_names', + 'DDDialysatePumpNames': '_create_dd_dialysate_pump_names', + 'DDHeaterNames': '_create_dd_heater_names', + 'DDLevelSensorNames': '_create_dd_level_sensor_names', + 'DDPistonPumpNames': '_create_dd_piston_pump_names', + 'DDPressureSensorNames': '_create_dd_pressure_sensor_names', + 'DDTemperatureSensorNames': '_create_dd_temperature_sensor_names', + 'DDValveNames': '_create_dd_valve_names', + 'DDMonitoredVoltages': '_create_dd_monitored_voltages', + + # Support enums + 'DDBalancingChamberStates': '_create_dd_balancing_chamber_states', + 'DDBalancingChamberSwitchStates': '_create_dd_balancing_chamber_switch_states', + 'DDBloodLeakStates': '_create_dd_blood_leak_states', + 'DDConcentratePumpAttributes': '_create_dd_concentrate_pump_attributes', + 'DDConcentratePumpStates': '_create_dd_concentrate_pump_states', + 'DDDialysatePumpAttributes': '_create_dd_dialysate_pump_attributes', + 'DDDialysatePumpsStates': '_create_dd_dialysate_pump_states', + 'DDHeaterStartStop': '_create_dd_heater_start_stop', + 'DDHeaterAttributes': '_create_dd_heater_attributes', + 'DDHeaterExecState': '_create_dd_heater_exec_states', + 'DDPistonPumpAttributes': '_create_dd_piston_pump_attributes', + 'DDValveStates': '_create_dd_valve_states', + } + + def __init__(self): + self.update_enums() + + + def __getattr__(self, name) -> DialinEnum: + if name in self._properties: + enum = getattr(self, self._properties[name])() + setattr(self, name, enum) + return enum + raise AttributeError(name) + + + def update_enums(self) -> None: + for prop_name in self._properties: + # Cleans the cached value + self.__dict__.pop(prop_name, None) + + # Reinitializing the enum as it's not in the cache + self.__getattr__(prop_name) + + + + # ================================================== Enum Creators: Operations ================================================== + def _create_dd_operation_modes(self): + members = { + 'MODE_FAUL': 0, # Fault Mode + 'MODE_SERV': 1, # Service Mode + 'MODE_INIT': 2, # Initialization & POST Mode + 'MODE_STAN': 3, # Standby Mode + 'MODE_PREG': 4, # Pre-generate Dialysate Mode + 'MODE_GEND': 5, # Generate Dialysate Mode + 'MODE_POSG': 6, # Post-generate Dialysate Mode + 'MODE_HEAT': 7, # Heat Disinfect Mode + 'MODE_HCOL': 8, # Cooling Mode + 'MODE_ROPS': 9, # RO Permeate Sample Mode + 'MODE_NLEG': 10, # Non-legal Mode - an illegitimate mode transition has occurred + 'NUM_OF_DD_MODES': 11, # Number of Modes for the DD + } + return unique(DialinEnum('DDOpModes', members)) + + + def _create_dd_fault_states(self): + members = { + 'DD_FAULT_STATE_START': 0, # DD fault start state + 'DD_FAULT_DEENERGIZED_STATE': 1, # DD fault de-energized state + 'DD_FAULT_ENERGIZED_STATE': 2, # DD fault energized state + 'NUM_OF_DD_FAULT_STATES': 3, # Number of fault mode states + } + return unique(DialinEnum('DDFaultStates', members)) + + + def _create_dd_fault_nvdata_states(self): + members = { + 'DD_FAULT_STATE_START': 0, # DD fault start state + 'DD_FAULT_STATE_RUN_NV_POSTS': 1, # DD fault run RTC and NV data management post + 'DD_FAULT_STATE_COMPLETE': 2, # DD fault complete + 'NUM_OF_DD_FAULT_NVDATA_STATES': 3, # Number of fault mode NV Data management states + } + return unique(DialinEnum('DDFaultNVDataStates', members)) + + + def _create_dd_service_states(self): + members = { + 'DD_SERVICE_STATE_START': 0, # Start service mode state + 'NUM_OF_DD_SERVICE_STATES': 1, # Number of service mode states + } + return unique(DialinEnum('DDServiceStates', members)) + + + def _create_dd_init_states(self): + members = { + 'DD_POST_STATE_START': 0, # Post Generate Dialysate Start State + 'DD_POST_STATE_FW_COMPATIBILITY': 1, # Firmware Compatibility State + 'DD_POST_STATE_FW_INTEGRITY': 2, # Firmware Integrity State + 'DD_POST_STATE_FPGA': 3, # FPGA State + 'DD_POST_STATE_NVDATAMGMT': 4, # Non-volatile Data Management State + 'DD_POST_STATE_TEMPERATURE_SENSORS': 5, # Temperature Sensors State + 'DD_POST_STATE_PRESSURES': 6, # Pressure Sensors State + 'DD_POST_STATE_DIALYSATE_PUMPS': 7, # Dialysate Pumps State + 'DD_POST_STATE_CONCENTRATE_PUMPS': 8, # Concentrate Pumps State + 'DD_POST_STATE_CONDUCTIVITY_SENSORS': 9, # Conductivity Sensors State + 'DD_POST_STATE_WATCHDOG': 10, # Watchdog State + 'DD_POST_STATE_SAFETY_SHUTDOWN': 11, # Safety Shutdown State + 'DD_POST_STATE_COMPLETED': 12, # Post Generate Dialysate Completed State + 'DD_POST_STATE_FAILED': 13, # Post Generate Dialysate Fail State + 'NUM_OF_DD_POST_STATES': 14, # Number of Post Generate Dialysate States + } + return unique(DialinEnum('DDInitStates', members)) + + + def _create_dd_standby_states(self): + members = { + 'DD_STANDBY_MODE_STATE_IDLE': 0, # Idle standby mode state + 'DD_STANDBY_MODE_STATE_PAUSE': 1, # Pause state + 'NUM_OF_DD_STANDBY_MODE_STATES': 2, # Number of standby mode states + } + return unique(DialinEnum('DDStandbyStates', members)) + + + def _create_dd_pregen_states(self): + members = { + 'DD_PRE_GEN_DIALYSATE_HYD_CHAMBER_FILL_CHECK': 0, # DD Pre-Gen Dialysate hyrochamber fill check + 'DD_PRE_GEN_WET_SELF_TEST': 1, # DD Pre-Gen Wet Self Test + 'DD_PRE_GEN_DIALYSATE_WAIT_FOR_GEND': 2, # DD Pre-Gen Dialysate Wait for Gen Dialysate state transition + 'NUM_OF_DD_PRE_GEN_DIALYSATE_STATES': 3, # Number of Pre-Gen Dialysate mode states + } + + return unique(DialinEnum('DDPreGenDialysateStates', members)) + + + def _create_dd_gen_states(self): + members = { + 'DD_GEND_STATE_START': 0, # Gen dialysate start state + 'DD_GEND_DIALYSATE_BYPASS_STATE': 1, # Gen dialysate - Bypass dialysate state + 'DD_GEND_DIALYSATE_DELIVERY_STATE': 2, # Gen dialysate - deliver dialysate state + 'DD_GEND_ISOLATED_UF_STATE': 3, # Gen dialysate - Isolated ultrafiltration state + 'DD_GEND_SPENT_CHAMBER_FILL_STATE': 4, # Gen dialysate - spent chamber fill state + 'DD_GEND_BICARB_CHAMBER_FILL_STATE': 5, # Gen dialysate - bicarb chamber fill state + 'DD_GEND_DIALYSATE_DELIVERY_PAUSE': 6, # Gen dialysate - dialysate delivery pause state + 'NUM_OF_DD_GEND_MODE_STATES': 7, # Number of gen dialysate states + } + + return unique(DialinEnum('DDGenDialysateModeStates', members)) + + + def _create_dd_postgen_states(self): + members = { + 'DD_POST_GEN_DIALYSATE_STATE_START': 0, # DD Post-Gen Dialysate state start + 'DD_POST_GEN_DIALYSATE_STATE_COMPLETE': 1, # DD Post-Gen Dialysate complete state + 'NUM_OF_DD_POST_GEN_DIALYSATE_STATES': 2, # Number of Post-Gen Dialysate mode states + } + + return unique(DialinEnum('DDPostGenDialysateStates', members)) + + + def _create_dd_heat_disinfect_states(self): + members = { + 'DD_HEAT_DISINFECT_STATE_START': 0, # Heat disinfect, start mode state + 'DD_HEAT_DISINFECT_STATE_COMPLETE': 1, # Heat disinfect, complete state + 'NUM_OF_DD_HEAT_DISINFECT_STATES': 2 # Number of heat disinfect mode states + } + return unique(DialinEnum('DDHeatDisinfectStates', members)) + + + def _create_dd_heater_cooling_states(self): + members = { + 'NUM_OF_DD_HEAT_COOL_STATES': 0, # Number of Heater Cooling states + } + return unique(DialinEnum('DDHeaterCoolingStates', members)) + + + def _create_dd_ro_permeate_states(self): + members = { + 'NUM_OF_RO_PERMEATE_STATES': 0, # Number of RO Permeate states + } + return unique(DialinEnum('DDROPermeateStates', members)) + + + def _create_dd_not_legal_states(self): + members = { + 'NUM_OF_NOT_LEGAL_STATES': 0, # Number of Not Legal states + } + return unique(DialinEnum('DDNotLegalStates', members)) + + + def _create_dd_event_list(self): + members = { + 'DD_EVENT_STARTUP': 0, # DD startup event + 'DD_EVENT_OP_MODE_CHANGE': 1, # DD Op mode change event + 'DD_EVENT_SUB_MODE_CHANGE': 2, # DD Op sub-mode change event + 'DD_EVENT_OPERATION_STATUS': 3, # DD operation status event + 'DD_EVENT_D6_LEVL_CHANGE': 4, # DD floater level change event + 'DD_EVENT_D63_LEVL_CHANGE': 5, # DD bicarb level change event + 'DD_EVENT_D46_LEVL_CHANGE': 6, # DD spent dialysate air seperation level change event + 'DD_EVENT_TD_COMMUNICATION_LOSS': 7, # DD TD communication loss + 'DD_EVENT_TEMPERATURE_DRIFT': 8, # DD dialysate temperature drift + 'DD_EVENT_BLOOD_LEAK_ZEROING_REQUEST': 9, # DD blood leak zeroing request + 'DD_EVENT_BLOOD_LEAK_ZEROING_REQUIRED': 10, # DD blood leak zeroing required + 'DD_EVENT_BLOOD_LEAK_NUM_OF_SET_POINT_CHECK_FAILURES': 11, # DD blood leak number of setpoint check failures + 'DD_EVENT_BLOOD_LEAK_SELF_TEST_RESULT': 12, # DD blood leak self test result + 'NUM_OF_DD_EVENT_IDS': 13, # Total number of DD events + } + return unique(DialinEnum('DDEventList', members)) + + + def _create_dd_event_data_types(self): + members = { + 'EVENT_DATA_TYPE_NONE': 0, # No Event Data Type + 'EVENT_DATA_TYPE_U32': 1, # Unsigned 32bit Event Data Type + 'EVENT_DATA_TYPE_S32': 2, # Signed 32bit Event Data Type + 'EVENT_DATA_TYPE_F32': 3, # Float 32bit Event Data Type + 'EVENT_DATA_TYPE_BOOL': 4, # Boolean Event Data Type + 'NUM_OF_EVENT_DATA_TYPES': 5, # Number of Event Data Types + } + return unique(DialinEnum('DDEventDataTypes', members)) + + + + # ================================================== Enum Creators: Names ================================================== + def _create_dd_concentrate_pump_names(self): + members = { + 'D11_CP1_ACID': 0, # Acid Concentrate Pump + 'D10_CP2_BICARB': 1, # Bicarbonate Concentrate Pump + 'D76_UF': 2, # Ultrafiltration Concentrate Pump + 'NUM_OF_CONCENTRATE_PUMPS': 3, # Number of Concentrate Pumps + } + return unique(DialinEnum('DDConcentratePumpNames', members)) + + + def _create_dd_conductivity_sensor_names(self): + members = { + 'D17_COND': 0, # Closed Loop Control of Dosing for D74 Conductivity Sensor + 'D27_COND': 1, # Closed Loop Control of Dosing for D29 Conductivity Sensor + 'D29_COND': 2, # Water, Bicarbonate, and Acid Collective Conductivity Sensor + 'D43_COND': 3, # Self Test Conductivity Sensor (not used for dialysate conductivity) + 'D74_COND': 4, # Water and Bicarbonate Collective Conductivity Sensor + 'D98_COND': 5, # D98 Conductivity Sensor + 'NUM_OF_CONDUCTIVITY_SENSORS': 6 # Number of Conductivity Sensors + } + return unique(DialinEnum('DDConductivitySensorNames', members)) + + + def _create_dd_dialysate_pump_names(self): + members = { + 'D12_PUMP': 0, # Fresh Dialysate Pump + 'D48_PUMP': 1, # Spent Dialysate Pump + 'NUM_OF_DIALYSATE_PUMPS': 2, # Number of Dialysate Pumps + } + return unique(DialinEnum('DDDialysatePumpNames', members)) + + + def _create_dd_heater_names(self): + members = { + 'D5_HEAT': 0, # Primary heater + 'D45_HEAT': 1, # Trimmer heater + 'NUM_OF_DD_HEATERS': 2, # Number of Heaters + } + return unique(DialinEnum('DDHeaterNames', members)) + + + def _create_dd_level_sensor_names(self): + if GlobalVariables().HW_BETA_1_9 == True: + members = { + 'D6_LEVEL': 0, # floater switch low, medium and high status + 'D63_LEVEL': 1, # bicarb level low or high status + 'D46_LEVEL': 2, # Spent dialysate air separation chamber level low or high status + 'D98_LEVEL': 3, # D98 Conductivity Level Sensor + 'NUM_OF_LEVELS': 4, # Number of Level Sensors + } + else: + members = { + 'D6_LEVEL': 0, # floater switch low, medium and high status + 'D63_LEVEL': 1, # bicarb level low or high status + 'D46_LEVEL': 2, # Spent dialysate air separation chamber level low or high status + 'D98_LEVEL': 3, # D98 Conductivity Level Sensor + 'NUM_OF_LEVELS': 4, # Number of Level Sensors + } + return unique(DialinEnum('DDLevelSensorNames', members)) + + + def _create_dd_piston_pump_names(self): + members = { + 'ACID': 0, # Acid piston pump + 'BICARB': 1, # Bicarbonate piston pump + 'UF': 2, # Ultrafiltration piston pump + 'NUM_OF_PISTON_PUMPS': 3, # Number of piston pumps + } + return unique(DialinEnum('DDPistonPumpNames', members)) + + + def _create_dd_pressure_sensor_names(self): + if GlobalVariables().HW_BETA_1_9 == True: + members = { + 'D9_PRES': 0, # Hydraulics outlet pressure (PHo/Pn) + 'D66_PRES': 1, # Dry Bicarb pressure (PDB/PCb) + 'D51_PRES': 2, # Spent Dialysate pressure (PDs) + 'D18_PRES': 3, # Fresh Dialysate pressure (PDf) + 'D41_PRES': 4, # Transmembrane pressure (Ptm) + 'D87_PRES': 5, # D87 Pressure Sensor + 'NUM_OF_PRESSURE_SENSORS': 6, # Number of pressure sensors + } + else: + members = { + 'D9_PRES': 0, # Hydraulics outlet pressure (PHo/Pn) + 'D66_PRES': 1, # Dry Bicarb pressure (PDB/PCb) + 'D51_PRES': 2, # Spent Dialysate pressure (PDs) + 'D18_PRES': 3, # Fresh Dialysate pressure (PDf) + 'D41_PRES': 4, # Transmembrane pressure (Ptm) + 'D87_PRES': 5, # D87 Pressure Sensor + 'NUM_OF_PRESSURE_SENSORS': 6, # Number of pressure sensors + } + return unique(DialinEnum('DDPressureSensorNames', members)) + + + def _create_dd_temperature_sensor_names(self): + if GlobalVariables().HW_BETA_1_9 == True: + members = { + 'D1_TEMP': 0, # Heat exchanger Inlet temperature sensor + 'D78_TEMP': 1, # Heat exchanger Outlet temperature sensor + 'D4_TEMP': 2, # Hydraulics primary heater temperature sensor + 'D50_TEMP': 3, # Trimmer heater temperature sensor + 'D99_TEMP': 4, # D98(D99) Conductivity sensor temperature value + 'BRD_TEMP': 5, # Barometric temperature sensor + 'D16_TEMP': 6, # D16(D17) Conductivity sensor temperature value + 'D28_TEMP': 7, # D28(D27) Conductivity sensor temperature value + 'D30_TEMP': 8, # D30(D29) Conductivity sensor temperature value + 'D44_TEMP': 9, # D44(D43) Conductivity sensor temperature value + 'D75_TEMP': 10, # D75(D74) Conductivity sensor temperature value + 'D99_TEMP': 11, # D98(D99) Conductivity sensor temperature value + 'D4_AVG_TEMP': 11, # D4 Filtered value + 'D50_AVG_TEMP': 12, # D50 Filtered value + 'D99_AVG_TEMP': 13, # D99 Filtered value + 'D28_AVG_TEMP': 14, # D28 Filtered value + 'D30_AVG_TEMP': 15, # D30 Filtered value + 'D9_TEMP': 16, # D9 Pressure sensor temperature value + 'D66_TEMP': 17, # D66 Pressure sensor temperature value + 'D51_TEMP': 18, # D51 Pressure sensor temperature value + 'D18_TEMP': 19, # D18 Pressure sensor temperature value + 'D41_TEMP': 20, # D41 Pressure sensor temperature value + 'D87_TEMP': 21, # D87 Pressure sensor temperature value + 'NUM_OF_TEMP_SENSORS': 22, # Number of Temperature Sensors + } + else: + members = { + 'D1_TEMP': 0, # Heat exchanger Inlet temperature sensor + 'D78_TEMP': 1, # Heat exchanger Outlet temperature sensor + 'D4_TEMP': 2, # Hydraulics primary heater temperature sensor + 'D50_TEMP': 3, # Trimmer heater temperature sensor + 'D99_TEMP': 4, # D98(D99) Conductivity sensor temperature value + 'BRD_TEMP': 5, # Barometric temperature sensor + 'D16_TEMP': 6, # D16(D17) Conductivity sensor temperature value + 'D28_TEMP': 7, # D28(D27) Conductivity sensor temperature value + 'D30_TEMP': 8, # D30(D29) Conductivity sensor temperature value + 'D44_TEMP': 9, # D44(D43) Conductivity sensor temperature value + 'D75_TEMP': 10, # D75(D74) Conductivity sensor temperature value + 'D99_TEMP': 11, # D98(D99) Conductivity sensor temperature value + 'D4_AVG_TEMP': 11, # D4 Filtered value + 'D50_AVG_TEMP': 12, # D50 Filtered value + 'D99_AVG_TEMP': 13, # D99 Filtered value + 'D28_AVG_TEMP': 14, # D28 Filtered value + 'D30_AVG_TEMP': 15, # D30 Filtered value + 'D9_TEMP': 16, # D9 Pressure sensor temperature value + 'D66_TEMP': 17, # D66 Pressure sensor temperature value + 'D51_TEMP': 18, # D51 Pressure sensor temperature value + 'D18_TEMP': 19, # D18 Pressure sensor temperature value + 'D41_TEMP': 20, # D41 Pressure sensor temperature value + 'D87_TEMP': 21, # D87 Pressure sensor temperature value + 'NUM_OF_TEMP_SENSORS': 22, # Number of Temperature Sensors + } + created_enum = DialinEnum('DDTemperatureSensorNames', members) + + # Add aliases + extend_enum(created_enum, 'FIRST_PRESSURE_SENSOR', created_enum.D9_TEMP.value) + extend_enum(created_enum, 'LAST_PRESSURE_SENSOR', created_enum.D87_TEMP.value if GlobalVariables().HW_BETA_1_9 == True else created_enum.D41_TEMP.value) + extend_enum(created_enum, 'FIRST_CONDUCTIVITY_SENSOR', created_enum.D16_TEMP.value) + extend_enum(created_enum, 'LAST_CONDUCTIVITY_SENSOR', created_enum.D75_TEMP.value) + extend_enum(created_enum, 'FIRST_AVERAGE_SENSOR', created_enum.D4_AVG_TEMP.value) + extend_enum(created_enum, 'LAST_AVERAGE_SENSOR', created_enum.D30_AVG_TEMP.value) + + # Add aliases to be searchable (listed when pressed TAB) + created_enum._member_names_.append('FIRST_PRESSURE_SENSOR') + created_enum._member_names_.append('LAST_PRESSURE_SENSOR') + created_enum._member_names_.append('FIRST_CONDUCTIVITY_SENSOR') + created_enum._member_names_.append('LAST_CONDUCTIVITY_SENSOR') + created_enum._member_names_.append('FIRST_AVERAGE_SENSOR') + created_enum._member_names_.append('FIRST_AVERAGE_SENSOR') + + return created_enum + + + def _create_dd_valve_names(self): + members = { + 'D14_VALV': 0, # Valve Hydraulics Outlet (D14) + 'D52_VALV': 1, # Valve Thermal Disinfect (D52) + 'D8_VALV': 2, # Valve Hydraulics Bypass (D8) + 'D54_VALV': 3, # Valve Rinse Port (D54) + 'D53_VALV': 4, # Valve Drain (D53) + 'D34_VALV': 5, # Valve Dialyzer Bypass (D34) + 'D64_VALV': 6, # Valve Purge 1 (D64) + 'D31_VALV': 7, # Valve Pressure Test (D31) + 'D65_VALV': 8, # Valve DryBcarb Inlet (D65) + 'D35_VALV': 9, # Valve Dialyzer Inlet (D35) + 'D40_VALV': 10, # Valve Dialyzer Outlet (D40) + 'D47_VALV': 11, # Valve Dialysate Out Purge 2 (D47) + 'D3_VALV': 12, # Valve Hydraulics Inlet (D3) + 'D80_VALV': 13, # Valve Dry Bicarb (D80) + 'D81_VALV': 14, # Valve De-scaler (D81) + 'D85_VALV': 15, # Valve De-scaler (D85) + 'D23_VALV': 16, # Balancing chamber Valve 1 (D23) + 'D19_VALV': 17, # Balancing chamber Valve 2 (D19) + 'D25_VALV': 18, # Balancing chamber Valve 3 (D25) + 'D21_VALV': 19, # Balancing chamber Valve 4 (D21) + 'D24_VALV': 20, # Balancing chamber Valve 5 (D24) + 'D20_VALV': 21, # Balancing chamber Valve 6 (D20) + 'D26_VALV': 22, # Balancing chamber Valve 7 (D26) + 'D22_VALV': 23, # Balancing chamber Valve 8 (D22) + 'D79_PMP_VALV': 24, # D79 pump mapped to Spare Valve 0 + 'D83_VALV': 25, # D83 De-scaler Valve mapped to Spare Valve 1 + 'D91_VALV': 26, # D91 De-scaler Valve mapped to Spare Valve 2 + 'SPARE3_VALV': 27, # Spare Valve 3 + 'SPARE4_VALV': 28, # Spare Valve 4 + 'SPARE5_VALV': 29, # Spare Valve 5 + 'D100_VALV': 30, # D100 De-scaler Valve mapped to Spare Valve 6 + 'SPARE7_VALV': 31, # Spare Valve 7 + 'NUM_OF_DD_VALVES': 32, # Number of Valves for the DD + } + return unique(DialinEnum('DDValveNames', members)) + + + def _create_dd_monitored_voltages(self): + members = { + 'MONITORED_LINE_1_2V': 0, # Processor voltage (1.2V) + 'MONITORED_LINE_3_3V': 1, # Logic voltage (3.3V) + 'MONITORED_LINE_5V_LOGIC': 2, # Logic voltage (5V) + 'MONITORED_LINE_24V_1': 3, # Actuators voltage (24V) + 'MONITORED_LINE_24V_2': 4, # Actuators regen voltage (24V) + 'MONITORED_LINE_FPGA_VCC_V': 5, # FPGA Vcc (3V) + 'MONITORED_LINE_FPGA_AUX_V': 6, # FPGA Vaux (3V) + 'MONITORED_LINE_FPGA_PVN_V': 7, # FPGA Vpvn (1V) + 'NUM_OF_MONITORED_VOLTAGE_LINES': 8, # Number of TD operation modes + } + return unique(DialinEnum('DDMonitoredVoltages', members)) + + + + # ================================================== Enum Creators: Support ================================================== + def _create_dd_balancing_chamber_states(self): + members = { + 'BAL_CHAMBER_STATE_START': 0, # Initial state of balancing chamber + 'BAL_CHAMBER_STATE1_FILL_START': 1, # Balancing chamber state 1 fill start state + 'BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL': 2, # Balancing Chamber state 1 Bicarb and acid dosing control state + 'BAL_CHAMBER_STATE1_FILL_END': 3, # Balancing Chamber state 1 fill end state + 'BAL_CHAMBER_STATE2_FILL_START': 4, # Balancing chamber state 2 fill start state + 'BAL_CHAMBER_STATE2_BICARB_ACID_DOSING_CNTRL': 5, # Balancing Chamber state 2 Bicarb and acid dosing control state + 'BAL_CHAMBER_STATE2_FILL_END': 6, # Balancing Chamber state 2 fill end state + 'NUM_OF_BAL_CHAMBER_EXEC_STATES': 7, # Number of balancing chamber states + } + return unique(DialinEnum('DDBalancingChamberStates', members)) + + + def _create_dd_balancing_chamber_switch_states(self): + members = { + 'BAL_CHAMBER_SW_STATE1': 0, # Balancing chamber switching state 1 (V2,V5 and V3, V8 open, rest closed) + 'BAL_CHAMBER_SW_STATE2': 1, # Balancing chamber switching state 2 ( V1,V6 and V4, V7 open, rest closed) + 'NUM_OF_BAL_CHAMBER_SW': 2, # Number of balancing chamber states + } + return unique(DialinEnum('DDBalancingChamberSwitchStates', members)) + + + def _create_dd_blood_leak_states(self): + members = { + 'BLOOD_LEAK_WAIT_FOR_POST_STATE': 0, # + 'BLOOD_LEAK_CHECK_SET_POINT_STATE': 1, # + 'BLOOD_LEAK_INIT_STATE': 2, # + 'BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE': 3, # + 'BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE': 4, # + 'BLOOD_LEAK_NORMAL_STATE': 5, # + 'BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE': 6, # + 'NUM_OF_BLOOD_LEAK_STATES': 7, # Number of blood leak states + } + return unique(DialinEnum('DDBloodLeakStates', members)) + + + def _create_dd_concentrate_pump_attributes(self): + members = { + 'CURRENT_STATE': 0, # Current State Concentrate Pump Attribute + 'CURRENT_SET_SPEED': 1, # Current Set Speed Concentrate Pump Attribute + 'MEASURED_SPEED': 2, # Measured Speed Concentrate Pump Attribute + 'TARGET_SPEED': 3, # Target Speed Concentrate Pump Attribute + 'PULSE_US': 4, # Hall Sensor Pulse Width (in micro seconds) Concentrate Pump Attribute + 'TARGET_REV_COUNT': 5, # Target Revolutions Concentrate Pump Attribute + 'MEASURED_REV_COUNT': 6, # Measured Revolutions Concentrate Pump Attribute + 'PARKED': 7, # Parked Concentrate Pump Attribute + 'PARK_FAULT': 8, # Park Fault Concentrate Pump Attribute + 'NUM_OF_D10_D11_CONCENTRATE_PUMP_ATTRIBUTES': 9, # Number of Acid (D11) and Bicarbonate (D10) Concentrate Pump Attributes + } + return unique(DialinEnum('DDConcentratePumpAttributes', members)) + + + def _create_dd_concentrate_pump_states(self): + members = { + 'CONCENTRATE_PUMP_OFF_STATE': 0, # Concentrate Pump Off State + 'CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE': 1, # Ramp to Target Speed Concentrate Pump State + 'CONCENTRATE_PUMP_CONTROL_TARGET_SPEED_STATE': 2, # Control Target Speed Concentrate Pump State + 'NUM_OF_CONCENTRATE_PUMP_STATES': 3, # Number of Concentrate Pump States + } + return unique(DialinEnum('DDConcentratePumpStates', members)) + + + def _create_dd_dialysate_pump_attributes(self): + members = { + 'TARGET_RPM': 0, # Target RPM Dialysate Pump Attribute + 'MEASURED_SPEED': 1, # Measured Speed Dialysate Pump Attribute + 'CURRENT_SPEED': 2, # Current Speed Dialysate Pump Attribute + 'STATE': 3, # State to command Dialysate Pump Attribute + 'TARGET_PRESSURE': 4, # Target Pressure Dialysate Pump Attribute + 'MEASURED_PRESSURE': 5, # Measured Pressure Dialysate Pump Attribute + 'MEASURED_CURRENT': 6, # Measured Current Dialysate Pump Attribute + 'CONTROL': 7, # Pump Run/Stop Control Pump Attribute + 'DIRECTION_ERROR_COUNT': 8, # Direction Error Count Dialysate Pump Attribute + 'MEASURED_DIRECTION': 9, # Measured Direction Dialysate Pump Attribute + 'NUM_OF_DIALYSATE_PUMP_ATTRIBUTES': 10, # Number of Dialysate Pump Attributes + } + return unique(DialinEnum('DDDialysatePumpAttributes', members)) + + + def _create_dd_dialysate_pump_states(self): + members = { + 'DIALYSATE_PUMP_OFF_STATE': 0, # Dialysate Pump Off State + 'DIALYSATE_PUMP_RAMP_UP_STATE': 1, # Dialysate Pump Ramp Up State + 'DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE': 2, # Dialysate Pump Control to Target State + 'NUM_OF_DIALYSATE_PUMP_STATES': 3, # Number of Dialysate Pump States + } + return unique(DialinEnum('DDDialysatePumpsStates', members)) + + + def _create_dd_heater_start_stop(self): + return unique(DialinEnum('DDHeaterStartStop', {'STOP': 0, 'START': 1})) + + + def _create_dd_heater_attributes(self): + members = { + 'HEAT_DUTY_CYCLE': 0, # Heat Duty Cycle Attribute for Heaters + 'HEAT_TARGET_TEMP': 1, # Target Temperature Attribute for Heaters + 'HEAT_STATE': 2, # State to command Attribute for Heaters + 'DUTY_CYCLE_COUNT': 3, # Duty Cycle Count Attribute for Heaters + 'PWM_PERIOD': 4, # Pulse Width Modulation Attribute for Heaters + 'ADJUSTED_TARGET_TEMP': 5, # Adjusted Target Temperature Attribute for Heaters + 'TARGET_TEMP_TD': 6, # Target Temperature Attribute for Heaters + 'NUM_OF_DD_HEATER_ATTRIBUTES': 7, # Number of Heater Attributes + } + return unique(DialinEnum('DDHeaterAttributes', members)) + + + def _create_dd_heater_exec_states(self): + members = { + 'HEATER_EXEC_STATE_OFF': 0, # Heater Execution Off State + 'HEATER_EXEC_STATE_RAMP_TO_TARGET': 1, # Heater Execution Ramp to Target State + 'HEATER_EXEC_STATE_CONTROL_TO_TARGET': 2, # Heater Execution Control to Target State + 'HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET': 3, # Heater Execution Control to Disinfection State + 'NUM_OF_HEATERS_EXEC_STATE': 4, # Number of Heater Execution States + } + return unique(DialinEnum('DDHeaterExecState', members)) + + + def _create_dd_piston_pump_attributes(self): + members = { + 'CONTROL_STATE': 0, # Control State for the Piston Pumps + 'SW_COUNTER': 1, # Software counter attribute for the Piston Pumps + 'CYCLE_COUNTER': 2, # Cycle Counter for the Piston Pumps + 'NUM_OF_PISTON_PUMP_ATTRIBUTES': 3, # Number of Piston Pump Attributes + } + return unique(DialinEnum('DDPistonPumpAttributes', members)) + + + def _create_dd_valve_states(self): + members = { + 'VALVE_STATE_CLOSED': 0, # Valve Closed State + 'VALVE_STATE_OPEN': 1, # Valve Open State + } + return unique(DialinEnum('DDValveStates', members)) + + + +# ================================================== Creates a singleton ================================================== +dd_enum_repository = DD_Defs() + +# Attach listener to update function +test_config_change.add_listener(dd_enum_repository.update_enums) Index: leahi_dialin/common/msg_ids.py =================================================================== diff -u -re16372ac648dd4efca346c889348b08c8653ee17 -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision e16372ac648dd4efca346c889348b08c8653ee17) +++ leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -125,9 +125,54 @@ MSG_ID_USER_UF_SETTINGS_CHANGE_CONFIRMATION_RESPONSE = 0x67 MSG_ID_DD_VOLTAGES_DATA = 0x68 MSG_ID_DD_RINSE_PUMP_DATA = 0x69 - MSG_ID_DD_DRY_BICART_DATA = 0x70 + MSG_ID_TD_TREATMENT_LOG_ALARM_EVENT = 0x6A + MSG_ID_TD_TREATMENT_LOG_EVENT = 0x6B + MSG_ID_TD_DATE_AND_TIME_REQUEST = 0x6C + MSG_ID_TD_DATE_AND_TIME_RESPONSE = 0x6D + MSG_ID_DD_DATE_AND_TIME_REQUEST = 0x6E + MSG_ID_DD_DATE_AND_TIME_RESPONSE = 0x6F + MSG_ID_FP_RO_REJECTION_RATIO_DATA = 0x71 + MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST = 0x72 + MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE = 0x73 + MSG_ID_UI_BOLUS_VOLUME_CHANGE_REQUEST = 0x74 + MSG_ID_TD_BOLUS_VOLUME_CHANGE_RESPONSE = 0x75 + MSG_ID_UI_DURATION_VALIDATE_REQUEST = 0x76 + MSG_ID_TD_DURATION_VALIDATE_RESPONSE = 0x77 + MSG_ID_UI_DURATION_CONFIRM_REQUEST = 0x78 + MSG_ID_TD_DURATION_CONFIRM_RESPONSE = 0x79 + MSG_ID_UI_TREATMENT_SET_POINTS_CHANGE_REQUEST = 0x7A + MSG_ID_TD_TREATMENT_SET_POINTS_CHANGE_RESPONSE = 0x7B + MSG_ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_REQUEST = 0x7C + MSG_ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESPONSE = 0x7D + MSG_ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_REQUEST = 0x7E + MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RESPONSE = 0x7F + MSG_ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMPERATURE_CHANGE_REQUEST = 0x80 + MSG_ID_TD_TREATMENT_SET_POINT_DIALYSATE_TEMPERATURE_CHANGE_RESPONSE = 0x81 + MSG_ID_TD_INSTITUTIONAL_RECORD_REQUEST = 0x82 + MSG_ID_TD_INSTITUTIONAL_RECORD_RESPONSE = 0x83 + MSG_ID_TD_ADJUST_INSTITUTIONAL_RECORD_REQUEST = 0x84 + MSG_ID_TD_ADJUST_INSTITUTIONAL_RECORD_RESPONSE = 0x85 + MSG_ID_TD_ADVANCED_INSTITUTIONAL_RECORD_REQUEST = 0x86 + MSG_ID_TD_ADVANCED_INSTITUTIONAL_RECORD_RESPONSE = 0x87 + MSG_ID_TD_ADVANCED_ADJUST_INSTITUTIONAL_RECORD_REQUEST = 0x88 + MSG_ID_TD_ADVANCED_ADJUST_INSTITUTIONAL_RECORD_RESPONSE = 0x89 + MSG_ID_TD_HEPARIN_REQUEST = 0x8A + MSG_ID_TD_HEPARIN_RESPONSE = 0x8B + MSG_ID_TD_HEPARIN_DATA = 0x8C + MSG_ID_TD_END_TREATMENT_REQUEST = 0x8D + MSG_ID_TD_END_TREATMENT_RESPONSE = 0x8E + MSG_ID_TD_RINSEBACK_PROGRESS = 0x8F + MSG_ID_UI_RINSEBACK_CMD_REQUEST = 0x90 + MSG_ID_TD_RINSEBACK_CMD_RESPONSE = 0x91 + MSG_ID_UI_ADJUST_DISPOSABLES_CONFIRM_REQUEST = 0X92 + MSG_ID_TD_ADJUST_DISPOSABLES_CONFIRM_RESPONSE = 0X93 + MSG_ID_UI_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_REQUEST = 0X94 + MSG_ID_TD_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_RESPONSE = 0X95 + MSG_ID_DD_DRY_BICART_DATA = 0x96 + MSG_ID_DD_PISTON_PUMP_CONTROL_DATA = 0xF0 + MSG_ID_TD_TESTER_LOGIN_REQUEST = 0x8000 MSG_ID_TD_SOFTWARE_RESET_REQUEST = 0x8001 MSG_ID_TD_SEND_TEST_CONFIGURATION = 0x8002 @@ -196,6 +241,7 @@ MSG_ID_TD_BARO_PRESSURE_OVERRIDE = 0x8041 MSG_ID_TD_TEMPERATURE_OVERRIDE = 0x8042 MSG_ID_TD_TEMPERATURE_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0x8043 + MSG_ID_TD_EJECTOR_OPT_SENSOR_OVERRIDE_REQUEST = 0x8044 MSG_ID_TD_TRAINING_TEST_OVERRIDE_REQUEST = 0x8999 @@ -282,11 +328,14 @@ MSG_ID_DD_VOLTAGE_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xA051 MSG_ID_DD_MONITORED_VOLTAGE_OVERRIDE_REQUEST = 0xA052 MSG_ID_DD_RINSE_PUMP_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xA053 - MSG_ID_DD_DRY_BICART_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xA054 - MSG_ID_DD_DRY_BICART_FILL_CYCLE_MAX_OVERRIDE_REQUEST = 0xA055 - MSG_ID_DD_DRY_BICART_FILL_REQUEST_OVERRIDE_REQUEST = 0xA056 - MSG_ID_DD_BICARB_CHAMBER_FILL_REQUEST_OVERRIDE_REQUEST = 0xA057 - MSG_ID_DD_BICART_DRAIN_REQUEST_OVERRIDE_REQUEST = 0xA058 + MSG_ID_DD_RINSE_PUMP_PWM_PERCENT_OVERRIDE_REQUEST = 0xA054 + MSG_ID_DD_RINSE_PUMP_TURN_ON_OFF_REQUEST = 0xA055 + MSG_ID_DD_SET_CONDUCTIVITY_MODEL_REQUEST = 0xA056 + MSG_ID_DD_DRY_BICART_DATA_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xA057 + MSG_ID_DD_DRY_BICART_FILL_CYCLE_MAX_OVERRIDE_REQUEST = 0xA058 + MSG_ID_DD_DRY_BICART_FILL_REQUEST_OVERRIDE_REQUEST = 0xA059 + MSG_ID_DD_BICARB_CHAMBER_FILL_REQUEST_OVERRIDE_REQUEST = 0xA05A + MSG_ID_DD_BICART_DRAIN_REQUEST_OVERRIDE_REQUEST = 0xA05B # Placeholder messages MSG_ID_DD_ALARM_STATE_OVERRIDE_REQUEST = 0xAF03 @@ -340,6 +389,15 @@ MSG_ID_FP_SET_TEST_CONFIGURATION = 0xB02D MSG_ID_FP_GET_TEST_CONFIGURATION = 0XB02E MSG_ID_FP_RESET_ALL_TEST_CONFIGURATIONS = 0XB02F + MSG_ID_FP_INLET_PRES_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xB030 + MSG_ID_FP_INLET_PRES_CHECK_TIME_OVERRIDE_REQUEST = 0xB031 + MSG_ID_FP_FILTERED_COND_SENSOR_READINGS_OVERRIDE_REQUEST = 0xB032 + # MSG_ID_FP_FILTERED_COND_SENSOR_TEMPERATURE_OVERRIDE_REQUEST = 0xB032 + MSG_ID_FP_SET_START_STOP_OVERRIDE_REQUEST = 0xB033 + MSG_ID_FP_RO_REJECTION_RATIO_PUBLISH_INTERVAL_OVERRIDE_REQUEST = 0xB034 + MSG_ID_FP_RO_FILTERED_REJECTION_RATIO_OVERRIDE_REQUEST = 0xB035 + MSG_ID_FP_DEF_STATUS_REQUEST = 0xB049 + MSG_ID_FP_DEF_STATUS_RESPONSE = 0xB04A MSG_ID_TD_DEBUG_EVENT = 0xFFF1 MSG_ID_DD_DEBUG_EVENT = 0xFFF2 Index: leahi_dialin/common/test_config_defs.py =================================================================== diff -u -re16372ac648dd4efca346c889348b08c8653ee17 -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/common/test_config_defs.py (.../test_config_defs.py) (revision e16372ac648dd4efca346c889348b08c8653ee17) +++ leahi_dialin/common/test_config_defs.py (.../test_config_defs.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -7,8 +7,8 @@ # # @file test_config_defs.py # -# @author (last) Dara Navaei -# @date (last) 16-Aug-2023 +# @author (last) Zoltan Miskolci +# @date (last) 21-Jan-2026 # @author (original) Dara Navaei # @date (original) 24-Apr-2023 # @@ -19,18 +19,23 @@ @unique -class DDTestConfigOptions(DialinEnum): - TEST_CONFIG_DISABLE_BC_PRES_ALARM = 0 # Test configuration disabling BC pressure alarms - TEST_CONFIG_ENABLE_DRY_BICART_FILL = 1 # Test configuration for enabling drybicart fill - NUM_OF_TEST_CONFIGS = 2 # Number of Test Configs +class DDFPTestConfigOptions(DialinEnum): + TEST_CONFIG_DD_FP_ENABLE_BETA_1_HW = 0 # (DD & FP) Test configuration using Beta 1 Hardware + TEST_CONFIG_DD_DISABLE_BC_PRES_ALARM = 1 # (DD) Test configuration disabling BC pressure alarms + TEST_CONFIG_DD_ENABLE_DRY_BICARB = 2 # (DD) Test configuration enable Dry Bicarb usage + TEST_CONFIG_DD_ENABLE_4WIRE_RINSE_PUMP = 3 # (DD) Test configuration enabling 4 wire rinse pump + TEST_CONFIG_FP_SKIP_PRE_GEN_FLUSH = 4 # (FP) Test configuration to skip pre-gen flush + TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP = 5 # (DD) Test configuration to use Diener 1000 pump for D48 + TEST_CONFIG_DD_ENABLE_D79_PWM_CONTROL = 6 # (DD) Test configuration to switch to PWM control for D79 + TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL = 7 # (DD) Test configuration to enable Chamber H Fill + TEST_CONFIG_DD_DISABLE_CONDUCTIVITY_ALARMS = 8 # (DD) Test configuration to disable DD conductivity alarms + TEST_CONFIG_FP_DISABLE_CONDUCTIVITY_ALARMS = 9 # (FP) Test configuration to disable FP conductivity alarms + TEST_CONFIG_DD_ENABLE_DOSING_OPEN_LOOP_CONTROL = 10 # (DD) Test configuration to switch to open loop control for concentrate dosing + TEST_CONFIG_DD_ENABLE_UF_TEMP_COMP = 11 # (DD) Test configuration to enable Ultrafiltration temperature compensation + TEST_CONFIG_DD_ENABLE_DRY_BICART_FILL = 12 # (DD) Test configuration enable Dry Bicart fill + NUM_OF_TEST_CONFIGS = 13 # Number of Test Configs @unique -class FPTestConfigOptions(DialinEnum): - TEST_CONFIG_BETA_HW = 0 # Test configuration using Beta Hardware - NUM_OF_TEST_CONFIGS = 1 # Number of Test Configs - -@unique class TDTestConfigOptions(DialinEnum): - TEST_CONFIG_FIRST = 0 # First test configuration (placeholder) + TEST_CONFIG_ENABLE_BETA_1_HW = 0 # Test configuration using Beta 1 Hardware NUM_OF_TEST_CONFIGS = 1 # Number of Test Configs - Index: leahi_dialin/dd/dialysate_delivery.py =================================================================== diff -u -rb3e7a0b4009eb7a95bbd1cbdf9a20024b519a3d7 -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision b3e7a0b4009eb7a95bbd1cbdf9a20024b519a3d7) +++ leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -7,20 +7,20 @@ # # @file dialysate_delivery.py # -# @author (last) Dara Navaei -# @date (last) 26-Feb-2024 +# @author (last) Zoltan Miskolci +# @date (last) 08-Jan-2026 # @author (original) Peter Lucia # @date (original) 02-Apr-2020 # ############################################################################ + import struct from .modules.alarms import DDAlarms from .modules.balancing_chamber import DDBalancingChamber from .modules.blood_leak import DDBloodLeak from .modules.concentrate_pump import DDConcentratePumps from .modules.conductivity_sensors import DDConductivitySensors -from .modules.constants import NO_RESET, RESET from .modules.dialysate_pump import DDDialysatePumps from .modules.events import DDEvents from .modules.gen_dialysate import DDGenDialysate @@ -41,13 +41,13 @@ from .proxies.ro_proxy import ROProxy from .proxies.td_proxy import TDProxy +from ..common.constants import NO_RESET +from ..common.dd_defs import dd_enum_repository from ..common.msg_defs import MsgIds, MsgFieldPositions, MsgFieldPositionsFWVersions -from ..common.dd_defs import DDOpModes +from ..common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels from ..utils.base import AbstractSubSystem, publish, LogManager -from ..utils.checks import check_broadcast_interval_override_ms -from ..utils.conversions import integer_to_bytearray, unsigned_short_to_bytearray, bytearray_to_integer, \ - bytearray_to_byte +from ..utils.conversions import integer_to_bytearray, bytearray_to_byte class DD(AbstractSubSystem): @@ -75,7 +75,6 @@ @param can_interface: (str) CANBus interface name, e.g. "can0" @param log_level: (str) Logging level, defaults to None """ - super().__init__() self._log_manager = LogManager(log_level=log_level, log_filepath=self.__class__.__name__ + ".log") self.logger = self._log_manager.logger @@ -106,7 +105,7 @@ self.dd_op_mode_timestamp = 0.0 self.dd_debug_events_timestamp = 0.0 self.dd_version_response_timestamp = 0.0 - self.dd_operation_mode = DDOpModes.MODE_INIT.value + self.dd_operation_mode = dd_enum_repository.DDOpModes.MODE_INIT.value self.dd_operation_sub_mode = 0 self.dd_logged_in = False self.dd_set_logged_in_status(False) @@ -145,7 +144,6 @@ @publish(["msg_id_dd_debug_event", "dd_debug_events_timestamp","dd_debug_events"]) def _handler_dd_debug_event_sync(self, message, timestamp = 0.0): - payload = message['message'] message_length = payload[self._DD_DEBUG_EVENT_MSG_LEN_INDEX] temp_message = '' @@ -165,6 +163,7 @@ if self.dd_debug_event_index == self._DD_DEBUG_EVENT_LIST_COUNT: self.dd_debug_event_index = 0 + @publish(["dd_logged_in"]) def dd_set_logged_in_status(self, logged_in: bool = False): """ @@ -174,6 +173,7 @@ """ self.dd_logged_in = logged_in + @publish(["msg_id_dd_op_mode_data", "dd_op_mode_timestamp","dd_operation_mode", "dd_operation_sub_mode"]) def _handler_dd_op_mode_sync(self, message, timestamp = 0.0): """ @@ -192,6 +192,7 @@ self.dd_operation_sub_mode = smode[0] self.dd_op_mode_timestamp = timestamp + @publish(["msg_id_dd_version_response", "dd_version, dd_fpga_version"]) def _handler_dd_version_response_sync(self,message, timestamp = 0.0): """ @@ -230,6 +231,28 @@ self.dd_version_response_timestamp = timestamp + + # def cmd_op_mode_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + # """ + # Constructs and sends the measured op mode broadcast interval override command + # Constraints: + # Must be logged into TD. + # Given interval must be non-zero and a multiple of the TD 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 + # """ + # return cmd_generic_broadcast_interval_override( + # ms = ms, + # reset = reset, + # channel_id = DenaliChannels.dialin_to_dd_ch_id, + # msg_id = MsgIds.MSG_ID_DD_OP_MODE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + # module_name = 'TD Operation Mode', + # logger = self.logger, + # can_interface = self.can_interface) + + def cmd_log_in_to_dd(self, resend: bool = False) -> int: """ Constructs and sends a login command via CAN bus. Login required before \n @@ -238,7 +261,6 @@ @param resend: (bool) if False (default), try to login once. Otherwise, tries to login indefinitely @return: 1 if logged in, 0 if log in failed """ - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, message_id=MsgIds.MSG_ID_DD_TESTER_LOGIN_REQUEST.value, payload=list(map(int, map(ord, self.DD_LOGIN_PASSWORD)))) @@ -261,6 +283,7 @@ self.logger.debug("Login Timeout!!!!") return False + def cmd_dd_set_operation_mode(self, new_mode: int = 0) -> int: """ Constructs and sends a set operation mode request command via CAN bus. @@ -272,31 +295,20 @@ @param new_mode: ID of operation mode to transition to @return: 1 if successful, zero otherwise - """ - payload = integer_to_bytearray(new_mode) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST.value, - payload=payload) + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST, + entity_name = 'DD Operation Mode', + override_text = dd_enum_repository.DDOpModes(new_mode).name, + logger = self.logger, + can_interface = self.can_interface) - self.logger.debug("Requesting DD mode change to " + str(new_mode)) - # Send message - received_message = self.can_interface.send(message) - - if received_message is not None: - if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: - self.logger.debug("Success: Mode change accepted") - else: - self.logger.debug("Failure: Mode change rejected.") - return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] - else: - self.logger.debug("DD mode change request Timeout!!!!") - return False - - def cmd_dd_software_reset_request(self) -> None: """ Constructs and sends an DD software reset request via CAN bus. @@ -305,18 +317,17 @@ @return: None """ + return cmd_generic_override( + payload = None, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_SOFTWARE_RESET_REQUEST, + entity_name = 'DD Software Reset', + override_text = '', + logger = self.logger, + can_interface = self.can_interface) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_SOFTWARE_RESET_REQUEST.value) - self.logger.debug("requesting DD software reset") - - # Send message - self.can_interface.send(message, 0) - self.logger.debug("Sent request to DD to reset...") - self.dd_set_logged_in_status(False) - - def cmd_dd_safety_shutdown_override(self, active: int, reset: int = NO_RESET) -> int: """ Constructs and sends an DD safety shutdown override command via CAN bus. @@ -326,28 +337,17 @@ @param active: int - True to activate safety shutdown, False to deactivate @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise - """ - rst = integer_to_bytearray(reset) saf = integer_to_bytearray(active) payload = rst + saf - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_SAFETY_SHUTDOWN_OVERRIDE_REQUEST.value, - payload=payload) - - self.logger.debug("overriding FP safety shutdown") - - # Send message - received_message = self.can_interface.send(message) - - if received_message is not None: - if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: - self.logger.debug("Safety shutdown signal overridden") - else: - self.logger.debug("Safety shutdown signal override failed.") - return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] - else: - self.logger.debug("Timeout!!!!") - return False + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST, + entity_name = 'DD Safety Shutdown', + override_text = str(active), + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/dd/modules/balancing_chamber.py =================================================================== diff -u -r0e852e50782a638367a1139f8c56cd8d722ba648 -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/dd/modules/balancing_chamber.py (.../balancing_chamber.py) (revision 0e852e50782a638367a1139f8c56cd8d722ba648) +++ leahi_dialin/dd/modules/balancing_chamber.py (.../balancing_chamber.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -7,23 +7,24 @@ # # @file balancing_chamber.py # -# @author (last) Micahel Garthwaite -# @date (last) 07-Mar-2023 +# @author (last) Zoltan Miskolci +# @date (last) 07-Jan-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ + import struct -from enum import unique from logging import Logger -from .constants import RESET, NO_RESET +from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish, DialinEnum -from leahi_dialin.utils.checks import check_broadcast_interval_override_ms +from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override +from leahi_dialin.protocols.CAN import DenaliChannels +from leahi_dialin.utils.base import AbstractSubSystem, publish from leahi_dialin.utils.conversions import integer_to_bytearray, float_to_bytearray + class DDBalancingChamber(AbstractSubSystem): """ Balancing Chamber @@ -33,7 +34,6 @@ def __init__(self, can_interface, logger: Logger): """ - @param can_interface: Denali Can Messenger object """ super().__init__() @@ -46,7 +46,6 @@ self.msg_id_dd_bal_chamber_data = MsgIds.MSG_ID_DD_BAL_CHAMBER_DATA.value self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_bal_chamber_data, self._handler_balancing_chamber_sync) - self.execution_state = 0 self.switching_state = 0 self.switching_frequency = 0.0 @@ -57,6 +56,7 @@ self.bal_chamber_switch_only_state = 0 self.dd_bal_chamber_timestamp = 0 + @publish(["msg_id_dd_bal_chamber_data", "execution_state", "switching_state", "switching_frequency", @@ -71,7 +71,6 @@ @param message: published balancing chamber data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] self.switching_state = struct.unpack('I', bytearray( @@ -91,6 +90,7 @@ self.dd_bal_chamber_timestamp = timestamp + def cmd_balancing_chamber_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: """ Constructs and sends the balancing chamber data broadcast interval override command @@ -102,31 +102,16 @@ @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ + return cmd_generic_broadcast_interval_override( + ms = ms, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_BAL_CHAMBER_DATA_PUBLISH_OVERRIDE_REQUEST, + module_name = 'DD Balancing Chamber', + logger = self.logger, + can_interface = self.can_interface) + - 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 - - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_BAL_CHAMBER_DATA_PUBLISH_OVERRIDE_REQUEST.value, - payload=payload) - - self.logger.debug("override DD Balancing Chamber data broadcast interval") - - # 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 - def cmd_switch_frequency_override(self, frequency: float, reset: int = NO_RESET) -> int: """ Constructs and sends the balancing chamber switch frequency override command @@ -136,34 +121,22 @@ @param frequency: float - frequency value to override switch frequency with @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise - """ - reset_byte_array = integer_to_bytearray(reset) freq = float_to_bytearray(frequency) payload = reset_byte_array + freq - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_BAL_CHAMBER_SWITCH_FREQ_OVERRIDE_REQUEST.value, - payload=payload) + return cmd_generic_override( + payload = payload, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_BAL_CHAMBER_SWITCH_FREQ_OVERRIDE_REQUEST, + entity_name = 'Switch Frequency', + override_text = str(frequency), + logger = self.logger, + can_interface = self.can_interface) - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(frequency) - self.logger.debug("override switch frequency " + ": " + str_res) - # 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 - def cmd_switch_only_start_stop_override(self, start_stop: int, flow: float) -> int: """ Constructs and sends the balancing chamber switch only start stop override command @@ -173,28 +146,22 @@ @param start_stop: int - value to start or stop switch ( start = 1, stop = 0 @param flow: float - flow rate in ml/min @return: 1 if successful, zero otherwise - """ - sts = integer_to_bytearray(start_stop) freq = float_to_bytearray(flow) payload = sts + freq - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_BC_SWITCH_ONLY_START_STOP_OVERRIDE_REQUEST.value, - payload=payload) + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_BC_SWITCH_ONLY_START_STOP_OVERRIDE_REQUEST, + entity_name = 'Switch Only Start' if start_stop == 1 else 'Switch Only Stop', + override_text = str(flow), + logger = self.logger, + can_interface = self.can_interface) - # 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 - def cmd_acid_dose_volume_override(self, volume: float, reset: int = NO_RESET) -> int: """ Constructs and sends the acid dose volume override command @@ -204,34 +171,22 @@ @param volume: float - volume value to override acid dose with @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise - """ - reset_byte_array = integer_to_bytearray(reset) vol = float_to_bytearray(volume) payload = reset_byte_array + vol - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_ACID_DOSING_VOLUME_OVERRIDE_REQUEST.value, - payload=payload) + return cmd_generic_override( + payload = payload, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_ACID_DOSING_VOLUME_OVERRIDE_REQUEST, + entity_name = 'Acid dose volume', + override_text = str(volume), + logger = self.logger, + can_interface = self.can_interface) - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(volume) - self.logger.debug("override acid dose volume to frequency " + ": " + str_res) - # 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 - def cmd_bicarb_dose_volume_override(self, volume: float, reset: int = NO_RESET) -> int: """ Constructs and sends the bicarb dose volume override command @@ -241,30 +196,17 @@ @param volume: float - volume value to override bicarb dose with @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise - """ - reset_byte_array = integer_to_bytearray(reset) vol = float_to_bytearray(volume) payload = reset_byte_array + vol - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_BICARB_DOSING_VOLUME_OVERRIDE_REQUEST.value, - payload=payload) - - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(volume) - self.logger.debug("override bicarb dose volume to frequency " + ": " + str_res) - - # 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 + return cmd_generic_override( + payload = payload, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_BICARB_DOSING_VOLUME_OVERRIDE_REQUEST, + entity_name = 'Bicarb dose volume', + override_text = str(volume), + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/dd/modules/valves.py =================================================================== diff -u -rb58eb26e4481c8c2ae3a7978d3564eaaee037ecd -rf66c019100e98b49cd94fa0a69951a1a7c952da0 --- leahi_dialin/dd/modules/valves.py (.../valves.py) (revision b58eb26e4481c8c2ae3a7978d3564eaaee037ecd) +++ leahi_dialin/dd/modules/valves.py (.../valves.py) (revision f66c019100e98b49cd94fa0a69951a1a7c952da0) @@ -7,24 +7,24 @@ # # @file valves.py # -# @author (last) Micahel Garthwaite -# @date (last) 17-Aug-2023 +# @author (last) Zoltan Miskolci +# @date (last) 07-Jan-2026 # @author (original) Peman Montazemi # @date (original) 19-May-2020 # ############################################################################ import struct -from enum import unique from logging import Logger from collections import OrderedDict -from .constants import NO_RESET +from leahi_dialin.common.constants import NO_RESET +from leahi_dialin.common.dd_defs import dd_enum_repository from leahi_dialin.common.msg_defs import MsgIds -from leahi_dialin.common.dd_defs import DDValveStates, DDValveNames +from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override from leahi_dialin.protocols.CAN import DenaliMessage, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish, DialinEnum -from leahi_dialin.utils.checks import check_broadcast_interval_override_ms +from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.utils.base import AbstractSubSystem, publish from leahi_dialin.utils.conversions import integer_to_bytearray # Valve states @@ -49,10 +49,8 @@ def __init__(self, can_interface, logger: Logger): """ - @param can_interface: Denali CAN Messenger object """ - super().__init__() self.can_interface = can_interface self.logger = logger @@ -65,48 +63,50 @@ self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_valves_states_data, self._handler_valves_sync) self.valve_states_all = 0x00000000 - self.d14_valv = {"id": DDValveNames.D14_VALV.value, "state": DEENERGIZED} - self.d52_valv = {"id": DDValveNames.D52_VALV.value, "state": DEENERGIZED} - self.d8_valv = {"id": DDValveNames.D8_VALV.value, "state": DEENERGIZED} - self.d54_valv = {"id": DDValveNames.D54_VALV.value, "state": DEENERGIZED} - self.d53_valv = {"id": DDValveNames.D53_VALV.value, "state": DEENERGIZED} - self.d34_valv = {"id": DDValveNames.D34_VALV.value, "state": DEENERGIZED} - self.d64_valv = {"id": DDValveNames.D64_VALV.value, "state": DEENERGIZED} - self.d31_valv = {"id": DDValveNames.D31_VALV.value, "state": DEENERGIZED} - self.d65_valv = {"id": DDValveNames.D65_VALV.value, "state": DEENERGIZED} - self.d35_valv = {"id": DDValveNames.D35_VALV.value, "state": DEENERGIZED} - self.d40_valv = {"id": DDValveNames.D40_VALV.value, "state": DEENERGIZED} - self.d47_valv = {"id": DDValveNames.D47_VALV.value, "state": DEENERGIZED} - self.d3_valv = {"id": DDValveNames.D3_VALV.value, "state": DEENERGIZED} - self.d80_valv = {"id": DDValveNames.D80_VALV.value, "state": DEENERGIZED} - self.d81_valv = {"id": DDValveNames.D81_VALV.value, "state": DEENERGIZED} - self.d85_valv = {"id": DDValveNames.D85_VALV.value, "state": DEENERGIZED} - self.d23_valv = {"id": DDValveNames.D23_VALV.value, "state": DEENERGIZED} - self.d19_valv = {"id": DDValveNames.D19_VALV.value, "state": DEENERGIZED} - self.d25_valv = {"id": DDValveNames.D25_VALV.value, "state": DEENERGIZED} - self.d21_valv = {"id": DDValveNames.D26_VALV.value, "state": DEENERGIZED} - self.d24_valv = {"id": DDValveNames.D24_VALV.value, "state": DEENERGIZED} - self.d20_valv = {"id": DDValveNames.D20_VALV.value, "state": DEENERGIZED} - self.d26_valv = {"id": DDValveNames.D21_VALV.value, "state": DEENERGIZED} - self.d22_valv = {"id": DDValveNames.D22_VALV.value, "state": DEENERGIZED} + self.d14_valv = {"id": dd_enum_repository.DDValveNames.D14_VALV.value, "state": DEENERGIZED} + self.d52_valv = {"id": dd_enum_repository.DDValveNames.D52_VALV.value, "state": DEENERGIZED} + self.d8_valv = {"id": dd_enum_repository.DDValveNames.D8_VALV.value, "state": DEENERGIZED} + self.d54_valv = {"id": dd_enum_repository.DDValveNames.D54_VALV.value, "state": DEENERGIZED} + self.d53_valv = {"id": dd_enum_repository.DDValveNames.D53_VALV.value, "state": DEENERGIZED} + self.d34_valv = {"id": dd_enum_repository.DDValveNames.D34_VALV.value, "state": DEENERGIZED} + self.d64_valv = {"id": dd_enum_repository.DDValveNames.D64_VALV.value, "state": DEENERGIZED} + self.d31_valv = {"id": dd_enum_repository.DDValveNames.D31_VALV.value, "state": DEENERGIZED} + self.d65_valv = {"id": dd_enum_repository.DDValveNames.D65_VALV.value, "state": DEENERGIZED} + self.d35_valv = {"id": dd_enum_repository.DDValveNames.D35_VALV.value, "state": DEENERGIZED} + self.d40_valv = {"id": dd_enum_repository.DDValveNames.D40_VALV.value, "state": DEENERGIZED} + self.d47_valv = {"id": dd_enum_repository.DDValveNames.D47_VALV.value, "state": DEENERGIZED} + self.d3_valv = {"id": dd_enum_repository.DDValveNames.D3_VALV.value, "state": DEENERGIZED} + self.d80_valv = {"id": dd_enum_repository.DDValveNames.D80_VALV.value, "state": DEENERGIZED} + self.d81_valv = {"id": dd_enum_repository.DDValveNames.D81_VALV.value, "state": DEENERGIZED} + self.d85_valv = {"id": dd_enum_repository.DDValveNames.D85_VALV.value, "state": DEENERGIZED} - self.d79_pmp_valv = {"id": DDValveNames.D79_PMP_VALV.value, "state": DEENERGIZED} - self.spare1_valv = {"id": DDValveNames.SPARE1_VALV.value, "state": DEENERGIZED} - self.spare2_valv = {"id": DDValveNames.SPARE2_VALV.value, "state": DEENERGIZED} - self.spare3_valv = {"id": DDValveNames.SPARE3_VALV.value, "state": DEENERGIZED} - self.spare4_valv = {"id": DDValveNames.SPARE4_VALV.value, "state": DEENERGIZED} - self.spare5_valv = {"id": DDValveNames.SPARE5_VALV.value, "state": DEENERGIZED} - self.spare6_valv = {"id": DDValveNames.SPARE6_VALV.value, "state": DEENERGIZED} - self.spare7_valv = {"id": DDValveNames.SPARE7_VALV.value, "state": DEENERGIZED} + self.d23_valv = {"id": dd_enum_repository.DDValveNames.D23_VALV.value, "state": DEENERGIZED} + self.d19_valv = {"id": dd_enum_repository.DDValveNames.D19_VALV.value, "state": DEENERGIZED} + self.d25_valv = {"id": dd_enum_repository.DDValveNames.D25_VALV.value, "state": DEENERGIZED} + self.d21_valv = {"id": dd_enum_repository.DDValveNames.D26_VALV.value, "state": DEENERGIZED} + self.d24_valv = {"id": dd_enum_repository.DDValveNames.D24_VALV.value, "state": DEENERGIZED} + self.d20_valv = {"id": dd_enum_repository.DDValveNames.D20_VALV.value, "state": DEENERGIZED} + self.d26_valv = {"id": dd_enum_repository.DDValveNames.D21_VALV.value, "state": DEENERGIZED} + self.d22_valv = {"id": dd_enum_repository.DDValveNames.D22_VALV.value, "state": DEENERGIZED} + self.d79_pmp_valv = {"id": dd_enum_repository.DDValveNames.D79_PMP_VALV.value, "state": DEENERGIZED} + self.d83_valv = {"id": dd_enum_repository.DDValveNames.D83_VALV.value, "state": DEENERGIZED} + self.d91_valv = {"id": dd_enum_repository.DDValveNames.D91_VALV.value, "state": DEENERGIZED} + self.spare3_valv = {"id": dd_enum_repository.DDValveNames.SPARE3_VALV.value, "state": DEENERGIZED} + self.spare4_valv = {"id": dd_enum_repository.DDValveNames.SPARE4_VALV.value, "state": DEENERGIZED} + self.spare5_valv = {"id": dd_enum_repository.DDValveNames.SPARE5_VALV.value, "state": DEENERGIZED} + self.d100_valv = {"id": dd_enum_repository.DDValveNames.D100_VALV.value, "state": DEENERGIZED} + self.spare7_valv = {"id": dd_enum_repository.DDValveNames.SPARE7_VALV.value, "state": DEENERGIZED} + # NOTE: The len function counts the enums with the same number only once. This is not the case in the DD valves # class because each valve must have a unique ID. - self.valve_states_enum = [0 for _ in range(len(DDValveNames))] + self.valve_states_enum = [0 for _ in range(len(dd_enum_repository.DDValveNames))] - for valve in DDValveNames.__members__: + for valve in dd_enum_repository.DDValveNames.__members__: self.valves_sensed_states[valve] = '' + def get_valve_states(self): """ Gets the valve states @@ -141,15 +141,16 @@ self.d22_valv.get("state", None), self.d79_pmp_valv.get("state", None), - self.spare1_valv.get("state", None), - self.spare2_valv.get("state", None), + self.d83_valv.get("state", None), + self.d91_valv.get("state", None), self.spare3_valv.get("state", None), self.spare4_valv.get("state", None), self.spare5_valv.get("state", None), - self.spare6_valv.get("state", None), + self.d100_valv.get("state", None), self.spare7_valv.get("state", None) ] + @staticmethod def sort_by_id(observation): """ @@ -159,7 +160,6 @@ @param observation: dictionary of the observed valve states @return: a list of tuples of the valve states """ - result = [] for key, value in observation.items(): if isinstance(value, dict): @@ -168,18 +168,19 @@ result = sorted(result, key=lambda each: each[1]) return result + @staticmethod def _binary_to_valve_state(binary) -> bool: """ @param binary: binary value @return: 1 = energized, otherwise de-energized """ - if binary != 0: return ENERGIZED else: return DEENERGIZED + @publish(["msg_id_dd_valves_states_data", "valve_states_all", "d14_valv", @@ -207,12 +208,12 @@ "d26_valv", "d22_valv", "d79_pmp_valv", - "spare1_valv", - "spare2_valv", + "D83_valv", + "D91_valv", "spare3_valv", "spare4_valv", "spare5_valv", - "spare6_valv", + "D100_valv", "spare7_valv", "valve_states_enum", "valves_sensed_states", @@ -228,7 +229,6 @@ vsa = struct.unpack('I', bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_ALL_VALVES])) self.valve_states_all = vsa[0] - vst = struct.unpack('H', bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_VALVES_STATES])) # Extract each valve state from U16 valves states using bit-masking self.d14_valv["state"] = self._binary_to_valve_state(vst[0] & 1) @@ -259,25 +259,47 @@ self.d22_valv["state"] = self._binary_to_valve_state(bcv[0] & 128) spv = struct.unpack('B', bytearray(message['message'][self.START_POS_SPARE_VALVES_STATES:self.END_POS_SPARE_VALVES_STATES])) - self.d79_pmp_valv["state"] = self._binary_to_valve_state(bcv[0] & 1) - self.spare1_valv["state"] = self._binary_to_valve_state(bcv[0] & 2) - self.spare2_valv["state"] = self._binary_to_valve_state(bcv[0] & 4) - self.spare3_valv["state"] = self._binary_to_valve_state(bcv[0] & 8) - self.spare4_valv["state"] = self._binary_to_valve_state(bcv[0] & 16) - self.spare5_valv["state"] = self._binary_to_valve_state(bcv[0] & 32) - self.spare6_valv["state"] = self._binary_to_valve_state(bcv[0] & 64) - self.spare7_valv["state"] = self._binary_to_valve_state(bcv[0] & 128) + self.d79_pmp_valv["state"] = self._binary_to_valve_state(spv[0] & 1) + self.d83_valv["state"] = self._binary_to_valve_state(spv[0] & 2) + self.d91_valv["state"] = self._binary_to_valve_state(spv[0] & 4) + self.spare3_valv["state"] = self._binary_to_valve_state(spv[0] & 8) + self.spare4_valv["state"] = self._binary_to_valve_state(spv[0] & 16) + self.spare5_valv["state"] = self._binary_to_valve_state(spv[0] & 32) + self.d100_valv["state"] = self._binary_to_valve_state(spv[0] & 64) + self.spare7_valv["state"] = self._binary_to_valve_state(spv[0] & 128) start = self.END_POS_SPARE_VALVES_STATES end = start + 1 for valve_id in self.valves_sensed_states: valve_state_number = struct.unpack('B', bytearray(message['message'][start:end]))[0] - self.valves_sensed_states[valve_id] = DDValveNames(valve_state_number).name + self.valves_sensed_states[valve_id] = dd_enum_repository.DDValveNames(valve_state_number).name start = end end += 1 self.dd_valves_states_timestamp = timestamp + + def cmd_valve_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the valve state override command. + Constraints: + Must be logged into DD. + Given interval must be non-zero and a multiple of the DD general task interval (50 ms). + + @param ms: unsigned int - broadcast interval (in ms) + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + return cmd_generic_broadcast_interval_override( + ms = ms, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_VALVE_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + module_name = 'DD Valves', + logger = self.logger, + can_interface = self.can_interface) + + 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. @@ -290,29 +312,23 @@ @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ - 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_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_VALVE_SENSED_STATE_OVERRIDE_REQUEST.value, - payload=payload) + valve_name = dd_enum_repository.DDValveNames(valve).name.split('_')[0] + return cmd_generic_override( + payload = payload, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_VALVE_SENSED_STATE_OVERRIDE_REQUEST, + entity_name = f'DD {valve_name} Valve sensed state', + override_text = str(state), + logger = self.logger, + can_interface = self.can_interface) - 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. @@ -325,29 +341,23 @@ @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ - 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_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_VALVE_STATE_OVERRIDE_REQUEST.value, - payload=payload) + valve_name = dd_enum_repository.DDValveNames(valve).name.split('_')[0] + return cmd_generic_override( + payload = payload, + reset = reset, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_VALVE_STATE_OVERRIDE_REQUEST, + entity_name = f'DD {valve_name} Valve state', + override_text = str(state), + logger = self.logger, + can_interface = self.can_interface) - self.logger.debug("Override valve 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_bc_valves_override(self, bcv1: bool, bcv2: bool, bcv3: bool, bcv4: bool, bcv5: bool, bcv6: bool, bcv7: bool, bcv8: bool) -> int: """ Constructs and sends the balancing chamber valve states override command. @@ -365,7 +375,6 @@ @param bcv8: bool - valve state for D22_VALV (true=open, false=closed) @return: 1 if successful, zero otherwise """ - valve = 0 if bcv1: valve = valve | 0x1 @@ -386,61 +395,17 @@ payload = integer_to_bytearray(valve) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_BC_VALVE_STATES_OVERRIDE_REQUEST.value, - payload=payload) + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_BC_VALVE_STATES_OVERRIDE_REQUEST, + entity_name = f'DD Balancing Chamber Valves state', + override_text = '', + logger = self.logger, + can_interface = self.can_interface) - self.logger.debug("Override balancing chamber valve states") - # 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_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: - """ - Constructs and sends the valve state override command. - Constraints: - Must be logged into DD. - Given interval must be non-zero and a multiple of the DD general task interval (50 ms). - - @param ms: unsigned int - broadcast interval (in ms) - @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 - - rst = integer_to_bytearray(reset) - ivl = integer_to_bytearray(ms) - payload = rst + ivl - - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_VALVE_PUBLISH_INTERVAL_OVERRIDE_REQUEST.value, - payload=payload) - - self.logger.debug("override valves states publish interval") - - # 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_valve_set_open_close(self, valve: int, state: int) -> int: """ Constructs and sends the valve open close command @@ -450,26 +415,18 @@ @param valve: unsigned int - valve ID @param state: int - value to command the valve @return: 1 if successful, zero otherwise - """ - vlv = integer_to_bytearray(valve) sts = integer_to_bytearray(state) payload = vlv + sts - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dd_ch_id, - message_id=MsgIds.MSG_ID_DD_VALVES_OPEN_CLOSE_STATE_OVERRIDE_REQUEST.value, - payload=payload) - - self.logger.debug("setting " + str(state) + " - for valve: " + str(valve)) - - # 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 \ No newline at end of file + valve_name = dd_enum_repository.DDValveNames(valve).name.split('_')[0] + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = DenaliChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_VALVES_OPEN_CLOSE_STATE_OVERRIDE_REQUEST, + entity_name = f'DD {valve_name} Valve state', + override_text = str(state), + logger = self.logger, + can_interface = self.can_interface)