########################################################################### # # Copyright (c) 2020-2023 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 dd_selection_handler.py # @author (last) Mohammad Suleiman # @date (original) 11--2023 # ############################################################################ from ..common import * from ..protocols.CAN import DenaliMessage, DenaliChannels from ..utils import * from time import time from random import random def reset(parent): rsp_id = MsgIds.MSG_ID_HD_OP_MODE_DATA rsp_payload = integer_to_bytearray(HDOpModes.MODE_INIT.value) rsp_payload += integer_to_bytearray(HDInitStates.POST_STATE_START.value) parent.demoSelection = 2 # setup event to change state on demoTimer parent.demoCount = 3 parent.demoGroupCount = None return rsp_id, rsp_payload def auto_transit_to_standby(parent): rsp_id = MsgIds.MSG_ID_HD_OP_MODE_DATA rsp_payload = integer_to_bytearray(HDOpModes.MODE_STAN.value) rsp_payload += integer_to_bytearray(HDStandbyStates.STANDBY_START_STATE.value) parent.demoSelection = 0 # wait for user return rsp_id, rsp_payload def filter_flush(parent): rsp_id = MsgIds.MSG_ID_HD_OP_MODE_DATA rsp_payload = integer_to_bytearray(HDOpModes.MODE_PRET.value) rsp_payload += integer_to_bytearray(PreTreatmentSubModes.HD_PRE_TREATMENT_WATER_SAMPLE_STATE.value) parent.demoSelection = 5 # = PreTreatmentDrySelfTestsStates.NUM_OF_DRY_SELF_TESTS_STATES.value - 1: parent.demoTimedIncValue = PreTreatmentPrimeStates.HD_PRIME_WAIT_FOR_USER_START_STATE.value - 1 # 1st pass is v+1 parent.demoSelection = 10 # TBD! setup event to change to ... Wait for User parent.demoCount = 0 # TBD! don't advance until user 'Start Prime' else: parent.demoCountdownId = MsgIds.MSG_ID_HD_DRY_SELF_TEST_PROGRESS_DATA # TBD setup above: parent.demoGroupCount = 14 * 4 # aggregate counter return rsp_id, rsp_payload def prime_circuits_with_dialysate(parent): rsp_id = MsgIds.MSG_ID_PRE_TREATMENT_STATE_DATA rsp_payload = struct.pack( "<" + str(PreTreatmentSubModes.NUM_OF_HD_PRE_TREATMENT_STATES.value + 1) + "i", PreTreatmentSubModes.HD_PRE_TREATMENT_PRIME_STATE.value, 0, # 2 No cartridge self-tests state 0, # 3 Consumable and cartridge installation state 0, # 0 Water sample state 0, # 1 Consumable self-tests state 0, # 4 Self-tests when the cartridge is dry state parent.demoTimedIncValue, # 5 Prime blood and dialysate circuits and run wet self-tests state 0, # 6 Re-circulate blood and dialysate circuits state 0, # 7 Patient connection state 0, 0 ) parent.demoCountdownId = MsgIds.MSG_ID_HD_PRIMING_STATUS_DATA parent.demoGroupCount = PreTreatmentPrimeStates.NUM_OF_HD_PRIME_STATES.value * 5 # aggregate count up to TBD! cleanup numbers if parent.demoTimedIncValue == PreTreatmentPrimeStates.HD_PRIME_WAIT_FOR_USER_START_STATE.value: parent.demoSelection = 0 # Wait for User # parent.demoGroupCounter = 0 # aggregate counter # TBD! could skip HD_PRIME_PAUSE? elif parent.demoTimedIncValue >= PreTreatmentPrimeStates.NUM_OF_HD_PRIME_STATES.value - 1: parent.demoTimedIncValue = None ## TBD!! parent.demoSelection = 11 # on next countdown transition parent.demoCount = 0 # immediate timeout # TBD!! Hack to make counter neat parent.demoGroupCounter = parent.demoGroupCount # aggregate counter # TBD else: # TBD parent.demoCountdownId = MsgIds.MSG_ID_HD_PRIMING_STATUS_DATA # TBD! need an aggregate time/timer return rsp_id, rsp_payload def recirculate_primed_circuits_1(parent): rsp_id = MsgIds.MSG_ID_PRE_TREATMENT_STATE_DATA rsp_payload = struct.pack( "<" + str(PreTreatmentSubModes.NUM_OF_HD_PRE_TREATMENT_STATES.value + 1) + "i", PreTreatmentSubModes.HD_PRE_TREATMENT_RECIRCULATE_STATE.value, 0, # 0 Water sample state 0, # 1 Consumable self-tests state 0, # 2 No cartridge self-tests state 0, # 3 Consumable and cartridge installation state 0, # 4 Self-tests when the cartridge is dry state 0, # 5 Prime blood and dialysate circuits and run wet self-tests state PreTreatmentRecircStates.PRE_TREATMENT_RECIRC_STATE.value, # 6 Re-circulate blood and dialysate circuits state 0, # 7 Patient connection state 0, 0 ) parent.demoSelection = 0 # Then wait for User parent.demoGroupCount = None # clear aggregate count return rsp_id, rsp_payload def recirculate_primed_circuits_2(parent): rsp_id = MsgIds.MSG_ID_PRE_TREATMENT_STATE_DATA rsp_payload = struct.pack( "<" + str(PreTreatmentSubModes.NUM_OF_HD_PRE_TREATMENT_STATES.value + 1) + "i", PreTreatmentSubModes.HD_PRE_TREATMENT_PATIENT_CONNECTION_STATE.value, 0, # 0 Water sample state 0, # 1 Consumable self-tests state 0, # 2 No cartridge self-tests state 0, # 3 Consumable and cartridge installation state 0, # 4 Self-tests when the cartridge is dry state 0, # 5 Prime blood and dialysate circuits and run wet self-tests state 0, # 6 Re-circulate blood and dialysate circuits state PreTreatmentPatientConnectionStates.PRE_TREATMENT_PAT_CONN_WAIT_FOR_UF_VOL_STATE.value, # 7 Patient connection state 0, 0 ) parent.demoSelection = 0 # Then wait for User parent.demoGroupCount = None # clear aggregate count return rsp_id, rsp_payload def start_treatment(parent): rsp_id = MsgIds.MSG_ID_HD_OP_MODE_DATA rsp_payload = integer_to_bytearray(HDOpModes.MODE_TREA.value) rsp_payload += integer_to_bytearray(0) parent.demoCountdownId = MsgIds.MSG_ID_HD_BLOOD_PRIME_PROGRESS_DATA parent.demoCount = 0 parent.demoCounter = 1 # parent.demoGroupCount = int(120 / 8) # TBD! fix const numbers # parent.demoGroupCount = -1 parent.demoSelection = 21 # Initiate Blood Prime parent.blood_prime_set_point_blood_flow = 20 return rsp_id, rsp_payload def blood_prime(parent): rsp_id = MsgIds.MSG_ID_TREATMENT_STATE_DATA rsp_payload = struct.pack("<10i", TreatmentStates.TREATMENT_BLOOD_PRIME_STATE.value, # 0 Treatment Submode 0, # 1 UF state 0, # 2 Saline bolus state 0, # 3 Hep state 0, # 4 Rinseback state 0, # 5 Recirc state 0, # 6 Blood Prime state 0, # 7 End state 0, # 8 Stop state 0, # 9 Dialysis state ) parent.demoSelection = 22 # Complete Blood Prime -> Dialysis parent.demoCountdownId = MsgIds.MSG_ID_HD_BLOOD_PRIME_PROGRESS_DATA parent.demoCount = int(120 / 8) # TBD! fix const numbers parent.demoCounter = -1 # give slight delay return rsp_id, rsp_payload def start_dialysis(parent): rsp_id = None rsp_payload = None # preset timing info parent.treatment_start_time_s = time() parent.cmd_set_treatment_time(sec_total=parent.treatment_time_sec, sec_elapsed=0, sec_remain=parent.treatment_time_sec) parent.heparin_out_ml = parent.heparin_bolus_ml if parent.heparin_bolus_ml > 0: parent.heparin_state = HeparinStates.HEPARIN_STATE_INITIAL_BOLUS # Initial heparin bolus delivery in progress else: parent.heparin_state = HeparinStates.HEPARIN_STATE_STOPPED # Heparin delivery stopped by alarm or not yet started parent.uf_state = TreatmentDialysisStates.DIALYSIS_START_STATE # 0 Treatment Submode parent.demoCount = parent.demoSpeed - 1 parent.demoGroupCount = parent.treatment_time_sec # TBD!! replace with user setting parent.demoGroupCounter = 0 parent.demoSelection = 29 # start dialysis return rsp_id, rsp_payload def enter_normal_uf(parent): rsp_id = MsgIds.MSG_ID_TREATMENT_STATE_DATA parent.uf_state = TreatmentDialysisStates.DIALYSIS_UF_STATE # 1 UF state parent.saline_state = SalineBolusStates.SALINE_BOLUS_STATE_IDLE # 2 Saline bolus state rsp_payload = struct.pack("<10i", TreatmentStates.TREATMENT_DIALYSIS_STATE.value, # 0 Treatment Submode parent.uf_state.value, # 1 UF state parent.saline_state.value, # 2 Saline bolus state parent.heparin_state.value, # 3 Hep state 0, # 4 Rinseback state 0, # 5 Recirc state 0, # 6 Blood Prime state 0, # 7 End state 0, # 8 Stop state 0, # 9 Dialysis state ) parent.demoSelection = 30 # ongoing data update return rsp_id, rsp_payload def dialysis_data_update(parent): rsp_id = None rsp_payload = None parent.blood_stop_time_s = time() # reset timer parent.treatment_stop_time_s = parent.blood_stop_time_s prev_heparin_state = parent.heparin_state prev_saline_state = parent.saline_state # MSG_ID_BLOOD_FLOW_DATA parent.blood_flow_measured_ml_per_min += (random() - 0.5) * 10 # TBD! replace magic numbers if parent.blood_flow_measured_ml_per_min > (parent.blood_flow_set_point_ml_per_min + 30): parent.blood_flow_measured_ml_per_min -= 5 parent.cmd_set_treatment_blood_flow_rate(flow_set_pt=parent.blood_flow_set_point_ml_per_min, measured_flow=parent.blood_flow_measured_ml_per_min, rot_speed=0, mot_speed=0, mc_speed=0, mc_current=0, pwm=0, rotor_count=0, pres_flow=parent.blood_flow_set_point_ml_per_min, rotor_hall=0) # MSG_ID_DIALYSATE_FLOW_DATA parent.dialysate_flow_measured_ml_per_min += (random() - 0.5) * 5 # TBD! replace magic numbers if parent.dialysate_flow_measured_ml_per_min > (parent.dialysate_flow_set_point_ml_per_min + 30): parent.dialysate_flow_measured_ml_per_min -= 5 parent.cmd_set_treatment_dialysate_flow_rate(flow_set_pt=parent.dialysate_flow_set_point_ml_per_min, measured_flow=parent.dialysate_flow_measured_ml_per_min, rot_speed=0.0, mot_speed=0.0, mc_speed=0.0, mc_current=0.0, pwm=0.0, rotor_count=0, presFlow=parent.dialysate_flow_set_point_ml_per_min, rotorHall=0) # MSG_ID_PRESSURE_OCCLUSION_DATA arterial_min_limit = int(parent.arterial_pressure_mid_mmHg - (parent.demo_treatment_params.data_int[ TreatmentParameters.TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW.value] / 2)) arterial_max_limit = int(parent.arterial_pressure_mid_mmHg + (parent.demo_treatment_params.data_int[ TreatmentParameters.TREATMENT_PARAM_ART_PRES_LIMIT_WINDOW.value] / 2)) venous_min_limit = int(parent.venous_pressure_mid_mmHg - (parent.demo_treatment_params.data_int[ TreatmentParameters.TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW.value] / 2)) venous_max_limit = int(parent.venous_pressure_mid_mmHg + (parent.demo_treatment_params.data_int[ TreatmentParameters.TREATMENT_PARAM_VEN_PRES_LIMIT_WINDOW.value] / 2)) parent.arterial_pressure_mmHg += (random() - 0.5) * 10 # TBD! replace magic wander numbers if parent.arterial_pressure_mmHg > (parent.arterial_pressure_mid_mmHg + 30): parent.arterial_pressure_mmHg -= 5 # Stay within limits if int(parent.arterial_pressure_mmHg) < arterial_min_limit: parent.arterial_pressure_mmHg = arterial_min_limit elif int(parent.arterial_pressure_mmHg) > arterial_max_limit: parent.arterial_pressure_mmHg = arterial_max_limit parent.venous_pressure_mmHg += (random() - 0.5) * 10 if parent.venous_pressure_mmHg > (parent.venous_pressure_mid_mmHg + 30): parent.venous_pressure_mmHg -= 5 # Stay within limits if int(parent.venous_pressure_mmHg) < venous_min_limit: parent.venous_pressure_mmHg = venous_min_limit elif int(parent.venous_pressure_mmHg) > venous_max_limit: parent.venous_pressure_mmHg = venous_max_limit parent.cmd_set_pressure_occlusion_data(arterial_prs=parent.arterial_pressure_mmHg, venous_prs=parent.venous_pressure_mmHg, blood_pump_occlusion=0, pressure_limit_state=0, arterial_min_limt=arterial_min_limit, arterial_max_limt=arterial_max_limit, venous_min_limit=venous_min_limit, venous_max_limit=venous_max_limit, arterial_long_filtered_pressure=parent.arterial_pressure_mmHg, venous_long_filtered_pressure=parent.venous_pressure_mmHg) # MSG_ID_RTC_EPOCH # tbd! # MSG_ID_DIALYSATE_OUT_FLOW_DATA # TBD!! parameters seem swapped and off by 1000x ?? # parent.cmd_set_treatment_ultrafiltration_outlet_flow_data(ref_uf_vol=parent.uf_volume_set_l, # measured_uf_vol=parent.uf_volume_out_l, # rot_speed=0.0, mot_speed=0.0, mc_speed=0.0, # mc_current=0.0, pwm=0.0) parent.uf_volume_out_l = min(parent.uf_volume_out_l + parent.uf_rate_l_per_sec, parent.uf_volume_set_l) parent.cmd_set_treatment_ultrafiltration_outlet_flow_data(ref_uf_vol=parent.uf_volume_out_l * 1000.0, measured_uf_vol=parent.uf_volume_set_l * 1000.0, rot_speed=0.0, mot_speed=0.0, mc_speed=0.0, mc_current=0.0, pwm=0.0, corr_offset=0.0, pump_calculated_rate=0.0, uf_calculated_rate=0.0, rotor_hall=0, current_uf_rate=(parent.uf_rate_l_per_sec * 60)) # MSG_ID_LOAD_CELL_READINGS # MSG_ID_TREATMENT_TIME if parent.treatment_time_sec != parent.demoGroupCount: # handle user change in treatment time parent.demoGroupCount = max(parent.treatment_time_sec, parent.demoGroupCounter) ctr_elapsed_sec = min(parent.demoGroupCounter, parent.demoGroupCount) ctr_remain_sec = parent.demoGroupCount - parent.demoGroupCounter parent.cmd_set_treatment_time(sec_total=parent.demoGroupCount, sec_elapsed=ctr_elapsed_sec, sec_remain=ctr_remain_sec) parent.demoGroupCounter -= 1 # TBD! effectively freeze countdown MAYBE? # MSG_ID_HD_HEPARIN_DATA_BROADCAST if ctr_remain_sec < (parent.heparin_stop_min * 60.0): parent.heparin_state = HeparinStates.HEPARIN_STATE_COMPLETED else: if parent.heparin_pause == False: parent.heparin_out_ml += parent.heparin_rate_ml_per_s * parent.demoSpeed parent.heparin_state = HeparinStates.HEPARIN_STATE_DISPENSING else: parent.heparin_state = HeparinStates.HEPARIN_STATE_PAUSED parent.heparin_expected_ml = (ctr_remain_sec - ( parent.heparin_stop_min * 60.0)) * parent.heparin_rate_ml_per_s + parent.heparin_out_ml parent.cmd_set_treatment_heparin_data(cumulative=parent.heparin_out_ml, required=parent.heparin_expected_ml) # sub selections within Dialysis Data Update if parent.demoSelection == 30: # Standard UF Dialysis . . . . . . . . . . parent.demoGroupCounter += 1 # TBD! effectively unfreeze countdown MAYBE? if parent.demoGroupCounter >= parent.demoGroupCount: # end of Treatment parent.demoGroupCount = None parent.demoGroupCounter = 0 parent.demoSelection = 40 elif parent.demoSelection == 31: # Saline Bolus . . . . . . . . . . . . . parent.uf_state = TreatmentDialysisStates.DIALYSIS_SALINE_BOLUS_STATE parent.saline_state = SalineBolusStates.SALINE_BOLUS_STATE_IN_PROGRESS # 2 Saline bolus state parent.demoSelection = 32 parent.salineVolume_ml = 0.0 # reset elif parent.demoSelection == 32: # Saline Bolus delivery rsp_id = MsgIds.MSG_ID_SALINE_BOLUS_DATA bolus_target_ml = parent.demo_treatment_params.data_int[ TreatmentParameters.TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML.value] new_volume_ml = bolus_target_ml - parent.salineVolume_ml if parent.salineBolusRate_mlpersec <= new_volume_ml: new_volume_ml = parent.salineBolusRate_mlpersec # incremental else: parent.demoSelection = 33 # done after this, so move on parent.salineVolume_ml += new_volume_ml parent.salineVolCum_ml += new_volume_ml rsp_payload = struct.pack("