Index: dialin/common/dg_defs.py =================================================================== diff -u -rf0cb1f298e3960769e0133172769deb9afe5a393 -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- dialin/common/dg_defs.py (.../dg_defs.py) (revision f0cb1f298e3960769e0133172769deb9afe5a393) +++ dialin/common/dg_defs.py (.../dg_defs.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -199,38 +199,47 @@ HEAT_DISINFECT_UI_STATE_COMPLETE = 9 NUM_OF_HEAT_DISINFECT_UI_STATES = 10 - @unique class DGChemicalDisinfectStates(DialinEnum): DG_CHEM_DISINFECT_STATE_START = 0 DG_CHEM_DISINFECT_STATE_DRAIN_R1 = 1 DG_CHEM_DISINFECT_STATE_DRAIN_R2 = 2 DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN = 3 DG_CHEM_DISINFECT_STATE_FLUSH_CIRCULATION = 4 - DG_CHEM_DISINFECT_STATE_FLUSH_R1_AND_R2 = 5 - DG_CHEM_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1 = 6 - DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R2 = 7 - DG_CHEM_DISINFECT_STATE_FLUSH_DRAIN_R1 = 8 - DG_CHEM_DISINFECT_STATE_PRIME_ACID_LINE = 9 - DG_CHEM_DISINFECT_STATE_FILL_WITH_WATER_AND_DISINFECTANT = 10 - DG_CHEM_DISINFECT_STATE_REMOVE_ACID_BOTTLE_FROM_UI = 11 - DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 = 12 - DG_CHEM_DISINFECT_STATE_FILL_R2_WITH_DISINFECTANT = 13 - DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 = 14 - DG_CHEM_DISINFECT_STATE_COOL_DOWN_HEATERS = 15 - DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1 = 16 - DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R2 = 17 - DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2 = 18 - DG_CHEM_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1 = 19 - DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2 = 20 - DG_CHEM_DISINFECT_STATE_RINSE_CIRCULATION = 21 - DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH = 22 - DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH = 23 - DG_CHEM_DISINFECT_STATE_COMPLETE = 24 - NUM_OF_DG_CHEM_DISINFECT_STATES = 25 + DG_CHEM_DISINFECT_STATE_PRIME_DISINFECTANT = 5 + DG_CHEM_DISINFECT_STATE_DISINFECTANT_FLUSH = 6 + DG_CHEM_DISINFECT_STATE_FILL_WITH_DISINFECTANT = 7 + DG_CHEM_DISINFECT_STATE_R2_DISINFECTANT_FILL_R1_DRAIN = 8 + DG_CHEM_DISINFECT_STATE_R1_DISINFECTANT_FILL_R2_DRAIN = 9 + DG_CHEM_DISINFECT_STATE_CANCEL_BASIC_PATH = 10 + DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH = 11 + DG_CHEM_DISINFECT_STATE_COMPLETE = 12 + NUM_OF_DG_CHEM_DISINFECT_STATES = 13 +@unique +class DGChemDisinfectFlushStates(DialinEnum): + DG_CHEM_DISINFECT_FLUSH_STATE_START = 0 + DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R1 = 1 + DG_CHEM_DISINFECT_FLUSH_STATE_DISINFECTANT_DRAIN_R2 = 2 + DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DRAIN = 3 + DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_DISINFECTANT_LINE = 4 + DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_UF = 5 + DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R2_TO_R1_DRAIN_R1 = 6 + DG_CHEM_DISINFECT_FLUSH_STATE_FLUSH_R1_TO_R2_DRAIN_R2 = 7 + DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_BASIC_PATH = 8 + DG_CHEM_DISINFECT_FLUSH_STATE_CANCEL_WATER_PATH = 9 + DG_CHEM_DISINFECT_FLUSH_STATE_COMPLETE = 10 + NUM_OF_DG_CHEM_DISINFECT_FLUSH_STATES = 11 + @unique +class DGChemDisinfectFlushUIStates(DialinEnum): + CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING = 0 + CHEM_DISINFECT_FLUSH_UI_STATE_FLUSH_AFTER_DISINFECT = 1 + CHEM_DISINFECT_FLUSH_UI_STATE_CANCEL_FLUSH = 2 + CHEM_DISINFECT_FLUSH_UI_STATE_COMPLETE = 3 + NUM_OF_CHEM_DISINFECT_FLUSH_UI_STATES = 4 +@unique class DGChemDisinfectUIStates(DialinEnum): CHEM_DISINFECT_UI_STATE_NOT_RUNNING = 0 CHEM_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT = 1 Index: dialin/common/msg_ids.py =================================================================== diff -u -rf9d050431231651a00d780bcaf98ddf2dabedf93 -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- dialin/common/msg_ids.py (.../msg_ids.py) (revision f9d050431231651a00d780bcaf98ddf2dabedf93) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -204,7 +204,11 @@ MSG_ID_HD_REQUEST_DG_ALARMS = 0xB5 MSG_ID_HD_REQUEST_DG_SERVICE_MODE = 0xB6 MSG_ID_DG_RTC_EPOCH = 0xB7 - + MSG_ID_DG_CHEM_DISINFECT_FLUSH_DATA = 0xC0 + MSG_ID_DG_CHEM_DISINFECT_FLUSH_TIME_DATA = 0xC1 + MSG_ID_DG_START_STOP_CHEM_DISINFECT_FLUSH = 0xC2 + MSG_ID_UI_CHEM_DISINFECT_FLUSH_CONFIRM = 0xC3 + MSG_ID_HD_CHEM_DISINFECT_FLUSH_CONFIRM_RESPONSE = 0xC4 MSG_ID_CAN_ERROR_COUNT = 0x999 MSG_ID_TESTER_LOGIN_REQUEST = 0x8000 Index: dialin/dg/chemical_disinfect_flush.py =================================================================== diff -u --- dialin/dg/chemical_disinfect_flush.py (revision 0) +++ dialin/dg/chemical_disinfect_flush.py (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -0,0 +1,85 @@ +########################################################################### +# +# Copyright (c) 2021-2022 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 flush.py +# +# @author (last) Micahel Garthwaite +# @date (last) 29-Jul-2022 +# @author (original) Steve Jarpe +# @date (original) 16-Apr-2021 +# +############################################################################ +import struct +from enum import unique +from logging import Logger + +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliChannels +from ..utils.base import AbstractSubSystem, publish +from ..common.dg_defs import DGChemDisinfectFlushStates, DGChemDisinfectFlushUIStates + + +class ChemicalDisinfectFlushMode(AbstractSubSystem): + """ + Chemical Disinfect Flush Mode class with APIs to set the timing of each of the stages. + """ + + def __init__(self, can_interface, logger: Logger): + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + self.flush_state = DGChemDisinfectFlushStates.DG_CHEM_DISINFECT_FLUSH_STATE_START.value + self.overall_elapsed_time = 0 + self.state_elapsed_time = 0 + self.flush_drain_line_volume_l = 0.0 + self.flush_UI_state = DGChemDisinfectFlushUIStates.CHEM_DISINFECT_FLUSH_UI_STATE_NOT_RUNNING.value + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_DG_CHEM_DISINFECT_FLUSH_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_chem_disinfect_flush_sync) + + def clear_flush_info(self) -> None: + """ + Clears public class properties that are updated by the handler. + Specifically properties updated by the DG broadcast message + MSG_ID_DG_FLUSH_DATA. + + @returns : none + """ + self.flush_state = DGChemDisinfectFlushStates.DG_FLUSH_STATE_START.value + self.overall_elapsed_time = 0 + self.state_elapsed_time = 0 + + @publish(["flush_state", "overall_elapsed_time", "state_elapsed_time", "flush_drain_line_volume_l", + "flush_UI_state"]) + def _handler_chem_disinfect_flush_sync(self, message: dict) -> None: + """ + Handles published flush message + + @param message: published flush data message + @returns none + """ + state = struct.unpack(' int: + """ + Constructs and sends the start/stop DG chemical disinfect flush command + + @param start: (bool) True = start chemical disinfect flush, False = stop chemical disinfect flush. + @return: non-zero integer if successful, False otherwise + """ + # 1 is to start + if start: + cmd = 1 + str_text = "Starting" + else: + cmd = 0 + str_text = "Stopping" + payload = integer_to_bytearray(cmd) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_START_STOP_CHEM_DISINFECT_FLUSH.value, + payload=payload) + + self.logger.debug(str_text + " DG chemical disinfect flush") + + 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_resend_dg_alarms(self) -> int: """ Constructs and sends the re-send DG alarms command Index: dialin/hd/alarms.py =================================================================== diff -u -rcd913c56192aee8e251d0486d044442411902def -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- dialin/hd/alarms.py (.../alarms.py) (revision cd913c56192aee8e251d0486d044442411902def) +++ dialin/hd/alarms.py (.../alarms.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -393,7 +393,6 @@ @return: none """ self.logger.debug("Alarm activated!") - alarm_id = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) data_typ_1 = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) data_1 = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3])) @@ -403,6 +402,7 @@ rank = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7])) clr_top_only = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8])) + self.logger.debug("Alarm ID: %d %d %d"%(alarm_id[0], data_1[0], data_2[0])) self.alarm_states[alarm_id[0]] = True self.alarm_conditions[alarm_id[0]] = True self.alarm_priorities[alarm_id[0]] = priority[0] Index: tests/dg_heaters_test.py =================================================================== diff -u -r3a70bfb451b74106348c064c34f19934aadd9119 -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- tests/dg_heaters_test.py (.../dg_heaters_test.py) (revision 3a70bfb451b74106348c064c34f19934aadd9119) +++ tests/dg_heaters_test.py (.../dg_heaters_test.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -27,8 +27,8 @@ dg.cmd_ui_request_dg_version() sleep(1) print(dg.dg_version) + dg.heaters.cmd_start_stop_primary_heater() - """ hd.ro_pump.cmd_ro_pump_set_point_override(120) Index: tests/dg_nvm_scripts.py =================================================================== diff -u -rf0cb1f298e3960769e0133172769deb9afe5a393 -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- tests/dg_nvm_scripts.py (.../dg_nvm_scripts.py) (revision f0cb1f298e3960769e0133172769deb9afe5a393) +++ tests/dg_nvm_scripts.py (.../dg_nvm_scripts.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -32,7 +32,7 @@ # Use cmd_set_dg_sw_config_record() set the changes back to firmware # This function requires an address for the excel report. Use the absolute address of your excel report like the # example below - #dg.sw_configs.cmd_update_dg_sw_config_record('/home/fw/projects/DG_NV_Records/2022-10-09-DG-SW-CONFIGS-Record.xlsx') + #dg.sw_configs.cmd_update_dg_sw_config_record('/home/fw/projects/DG_NV_Records/2022-11-29-DG-SW-CONFIGS-Record.xlsx') # Use this function to reset the configuration records to all be 0 #dg.sw_configs.cmd_reset_dg_sw_config_record() Index: tests/dg_tests.py =================================================================== diff -u -rf0cb1f298e3960769e0133172769deb9afe5a393 -rc179a1b072005028cb495911f463b2bfcd9aa1d2 --- tests/dg_tests.py (.../dg_tests.py) (revision f0cb1f298e3960769e0133172769deb9afe5a393) +++ tests/dg_tests.py (.../dg_tests.py) (revision c179a1b072005028cb495911f463b2bfcd9aa1d2) @@ -21,6 +21,7 @@ from dialin.common.dg_defs import DGHeatDisinfectStates, DGHeatDisinfectUIStates from dialin.dg.heat_disinfect import HeatCancellationModes from dialin.common.dg_defs import DGChemicalDisinfectStates, DGChemDisinfectUIStates +from dialin.common.dg_defs import DGChemDisinfectFlushStates, DGChemDisinfectFlushUIStates from dialin.dg.chemical_disinfect import ChemCancellationModes from dialin.dg.drain_pump import DrainPumpStates from dialin.dg.thermistors import ThermistorsNames @@ -67,6 +68,11 @@ hd.alarms.alarm_top)) return info +def get_chemical_disinfect_flush_mode_info(): + info = ('State, {}, Overall_elapsed_time, {}, State_elapsed_time, {}, Drain_vol, {:5.3f}, Top_alarm, {}, ' + .format(DGChemDisinfectFlushStates(dg.chemical_disinfect_flush.flush_state).name, dg.chemical_disinfect_flush.overall_elapsed_time, dg.chemical_disinfect_flush.state_elapsed_time, + dg.chemical_disinfect_flush.flush_drain_line_volume_l, hd.alarms.alarm_top)) + return info def get_heat_disinfect_mode_info(): info = ('State, {}, Overall_elapsed_time, {}, State_elapsed_time, {}, Disinfect_elapsed_time, {}, ' @@ -83,10 +89,8 @@ info = ('State, {}, Overall_elapsed_time, {}, State_elapsed_time, {}, Drain_vol, {:5.3f}, Top_alarm, {}, ' .format(DGFlushStates(dg.flush.flush_state).name, dg.flush.overall_elapsed_time, dg.flush.state_elapsed_time, dg.flush.flush_drain_line_volume_l, hd.alarms.alarm_top)) - return info - def get_hd_run_info(): info = ('HD_op_mode, {}, HD_sub_mode, {}, Top_alarm, {}, Target_UF_ml, {:5.3f}, Meas_UF_ml, {:5.3f}, ' 'Wet_test_state, {}, Post_tx_state, {}, Post_tx_drain_state, {}, Prime_state, {}, Pre_Tx_rsrvr_state, {}, ' @@ -556,9 +560,10 @@ ro = get_ro_info() temp = get_temperature_sensors_info() heaters = get_heaters_info() - fans = get_dg_fans_info() + #fans = get_dg_fans_info() - var = disinfect + load_cell + conc + drain + ro + temp + heaters + fans + valves + '\r' + #var = disinfect + load_cell + conc + drain + ro + temp + heaters + fans + valves + '\r' + var = disinfect + load_cell + conc + drain + ro + temp + heaters + valves + '\r' print(var) f.write(var) @@ -579,7 +584,50 @@ dg.hd_proxy.cmd_start_stop_dg_chemical_disinfect(start=False) f.close() +def run_chem_disinfect_flush_mode(): + complete_counter = 1 + f = open("/home/fw/projects/dialin/tests/chem_disinfect_flush_mode.log", "w") + dg.hd_proxy.cmd_start_stop_dg_chemical_disinfect_flush() + #dg.cmd_dg_software_reset_request() + try: + while True: + flush = get_chemical_disinfect_flush_mode_info() + load_cell = get_load_cells_info() + drain = get_drain_states_info() + ro = get_ro_info() + conc = get_concentrate_pumps_info() + valves = get_dg_valves_states() + + var = flush + load_cell + drain + ro + conc + valves + '\r' + + print(var) + f.write(var) + sleep(1) + + # If the mode came back to standby or standby solo + if dg.dg_operation_mode == 3 or dg.dg_operation_mode == 4: + + if complete_counter == 1: + dg.hd_proxy.cmd_start_stop_dg_chemical_disinfect_flush() + # Write a few more complete states to make sure the complete state items are recorded + if complete_counter == 3: + f.close() + #events = dg.events.get_dg_events(2, 60) + #for event in events: + # print(event) + break + + complete_counter += 1 + + except KeyboardInterrupt: + dg.hd_proxy.cmd_start_stop_dg_chemical_disinfect_flush(start=False) + f.close() + #events = dg.events.get_dg_events(2, 50) + #for event in events: + # print(event) + + def cmd_set_disinfect_ui_screen(): hd = HD() sleep(0.5) @@ -607,7 +655,6 @@ valves = get_dg_valves_states() var = flush + uv_reactors + load_cell + drain + ro + conc + valves + '\r' - print(var) f.write(var) sleep(1) @@ -694,6 +741,8 @@ #run_chemical_disinfect() + run_chem_disinfect_flush_mode() + #run_dg() # cmd_set_disinfect_ui_screen() @@ -702,10 +751,10 @@ #collect_hd_treatment() - while True: + #while True: #print(get_hd_fans_info(), get_dg_fans_info(), get_temperature_sensors_info()) - print(get_dg_valves_states()) - sleep(1) + # print(get_dg_valves_states()) + # sleep(1) #while True: # print(dg.rtc.get_rtc_epoch(), hd.rtc.get_rtc_epoch())