Index: dialin/common/hd_defs.py =================================================================== diff -u -rd3a22e97fad0b715b1e9fba138236334ae7dbb6d -r151e5a7372d787218e39163e564c8e5dbe8a35e0 --- dialin/common/hd_defs.py (.../hd_defs.py) (revision d3a22e97fad0b715b1e9fba138236334ae7dbb6d) +++ dialin/common/hd_defs.py (.../hd_defs.py) (revision 151e5a7372d787218e39163e564c8e5dbe8a35e0) @@ -382,8 +382,8 @@ TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR = 15 TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML = 16 TREATMENT_PARAM_DIALYSATE_TEMPERATURE_C = 17 - TREATMENT_PARAM_UF_VOLUME_L = 18 - NUM_OF_TREATMENT_PARAMS = 19 +# TBD!!! TREATMENT_PARAM_UF_VOLUME_L = 18 + NUM_OF_TREATMENT_PARAMS = 18 @unique class PowerOffCommands(DialinEnum): Index: dialin/ui/hd_simulator.py =================================================================== diff -u -r57b6e85f4d6c2d07fee8a1710a41513a51bc09f2 -r151e5a7372d787218e39163e564c8e5dbe8a35e0 --- dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision 57b6e85f4d6c2d07fee8a1710a41513a51bc09f2) +++ dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision 151e5a7372d787218e39163e564c8e5dbe8a35e0) @@ -14,7 +14,6 @@ # ############################################################################ import enum -from time import sleep from typing import Callable from inspect import signature from . import messageBuilder @@ -26,6 +25,7 @@ from random import random from copy import deepcopy import threading as threadsHere +from time import time, sleep #from math import isclose def catch_exception(f): @@ -58,40 +58,6 @@ NUM_TREATMENT_PARAMETERS = 19 instance_count = 0 - demoTimer: threadsHere.Timer - demoCounter = 0 - demoCount = 1 - demoGroupCounter = 0 - demoGroupCount = None - demoSpeed = 1 # count multiplier - demoSelection = 1 - demoTimedIncValue = None - demoCountdownId = None - demoCountdownChannel = None - demoSemaphore = Semaphore(1) - - blood_flow_measured_ml_per_min = 188.8 - blood_flow_set_point_ml_per_min = 190 - dialysate_flow_measured_ml_per_min = 229.9 - dialysate_flow_set_point_ml_per_min = 250 - arterial_pressure_mmHg = -80.8 - arterial_pressure_mid_mmHg = -50.0 - venous_pressure_mmHg = 233.3 - venous_pressure_mid_mmHg = 200.0 - treatment_time_sec = 60 * 100 - uf_volume_l = 0 - uf_volume_set_l = 1.2 - uf_stop_time_sec = 60 * 2 - uf_rate_l_per_sec = uf_volume_set_l / (treatment_time_sec - uf_stop_time_sec) - salineVolume_mL = 0.0 - salineVolCum_mL = 0.0 - rinseback_volume_set_mL = 250 - rinseback_volume_out_mL = 0 - rinseback_volume_all_ml = 0 - rinsebackVelocity_mL_per_sec = 100.0 / 60.0 - hep_rate_ml_per_hr = 0 - hep_bolus_ml = 0 - MAX_UF_RATE_ML_PER_HR = 1000.0 MAX_UF_RATE_ML_PER_SEC = MAX_UF_RATE_ML_PER_HR / 3600 MAX_UF_ML_PER_TX = 7000.0 @@ -121,19 +87,55 @@ @param console_out: (bool) If True, write each dialin message to the console. """ super().__init__() + HDSimulator.instance_count = HDSimulator.instance_count + 1 - self.demoTimer = threadsHere.Timer(1.0, self.run_demoTimer_timeout) - self.demoTimer.start() - # self.demoTimer = Timer() - # self.demoTimer.start(1000) - # self.demoTimer.timeout.connect() - self.demoTimedIncValue = None - self.demoCountdownId = None - self.demoCountdownChannel = None + self.demoCounter = 0 + self.demoCount = 1 + self.demoGroupCounter = 0 + self.demoGroupCount = None + self.demoSpeed = 1 # count multiplier + self.demoSelection = 1 # current timer handling state + self.demoTimedIncValue = None # value incremented on step of GroupCout, used in progress messages + self.demoCountdownId = None # progress message ID to send while counting down + self.demoCountdownChannel = None # used to fake as DG sometimes + # default treatment settings, calculated parameters, accumulated status, and simulated data + self.blood_flow_measured_ml_per_min = 188.8 # simulation + self.blood_flow_set_point_ml_per_min = 190 # setting + self.dialysate_flow_measured_ml_per_min = 229.9 # simulation + self.dialysate_flow_set_point_ml_per_min = 250 # setting + self.arterial_pressure_mmHg = -80.8 # simulation + self.arterial_pressure_mid_mmHg = -50.0 # setting + self.venous_pressure_mmHg = 233.3 # simulation + self.venous_pressure_mid_mmHg = 200.0 # param + self.treatment_time_sec = 60 * 100 # setting + self.uf_volume_set_l = 1.2 # setting + self.uf_volume_out_l = 0 # status + self.uf_stop_time_sec = 60 * 2 # param + self.uf_rate_l_per_sec = 0.001 # param + self.salineVolume_ml = 0.0 # status + self.salineVolCum_ml = 0.0 # status + self.salineVolMax_ml = 800.0 # fixed R TBD! not enforced + self.salineBolusRate_mlpersec = 150.0 / 60.0 # fixed R + self.treatment_start_time_s = 0.0 # simulation R + self.treatment_stop_time_s = 0.0 # simulation R + self.blood_stop_time_s = 0.0 # simulation R + self.rinseback_volume_set_ml = 80 + 120 # setting + self.rinseback_volume_out_ml = 0 # status + self.rinseback_volume_all_ml = 0 # status + self.rinsebackVelocity_ml_per_sec = 100.0 / 60.0 # param + self.rinsebackVelocity_max_ml_per_sec = 150.0 / 60.0 # fixed R + self.rinsebackVelocity_min_ml_per_sec = 50.0 / 60.0 # fixed R + self.hep_rate_ml_per_hr = 0 # setting + self.hep_bolus_ml = 0 # setting + self.hep_stop_min = 0 # setting + self.hep_out_ml = 0 # status + self.demo_treatment_params = DenaliData() + self.demoSemaphore = Semaphore(1) # keep message and timer handling separate + self.auto_response = auto_response self._log_manager = LogManager(log_level=log_level, log_filepath=self.__class__.__name__ + ".log") self.logger = self._log_manager.logger @@ -159,6 +161,10 @@ # initialize variables that will be populated by UI version response self.ui_version = None + # start timer handler + self.demoTimer = threadsHere.Timer(1.0, self.run_demoTimer_timeout) + self.demoTimer.start() + def set_ui_all_publication(self, function_ptr: Callable) -> None: """ Allows later addition of publication to the HDSimulator @@ -213,7 +219,7 @@ def get_message_list_data(message: dict) -> DenaliData: ret_data = DenaliData() offset = MsgFieldPositions.START_POS_FIELD_1 - m_num_p = int( (len(message['message']) - offset) / 4 ) + m_num_p = min(message['message'][DenaliMessage.PAYLOAD_LENGTH_INDEX], int( (len(message['message']) - offset) / 4 )) ret_data.data_num = m_num_p ret_data.data_int[0:m_num_p] = struct.unpack('{}i'.format(m_num_p), bytearray(message['message'][offset:offset+m_num_p*4])) ret_data.data_float[0:m_num_p] = struct.unpack('{}f'.format(m_num_p), bytearray(message['message'][offset:offset+m_num_p*4])) @@ -252,6 +258,7 @@ print("generic handler:", MsgIds(msg_id).name, message) params = self.get_message_list_data(message) # convert payload data + # RESET/JUMP FORWARD DIALOG HANDLER ------------------------------- if (msg_id == MsgIds.MSG_ID_UI_CONFIRMATION_RESULT.value) and \ (params.data_int[0] == 99) and \ (params.data_int[1] == EResponse.Accepted): # TBD! Use const for 99 @@ -272,16 +279,18 @@ rsp_payload = integer_to_bytearray(98) # TBD! Use const for 99 rsp_payload += integer_to_bytearray(3) # TBD use consts rsp_payload += integer_to_bytearray(0) - if params.data_int[1] == EResponse.Accepted: + if params.data_int[1] == EResponse.Accepted: # Reset the Demo self.demoSelection = 1 # setup event to change Mode self.demoCount = 0 self.demoCounter = 1 - else: # EResponse.Rejected + else: # EResponse.Rejected - Just Jump Forward on any current counter self.demoSelection = self.pause_demoSelection # setup event to change state on demoTimer self.demoCountdownId = self.pause_demoId self.demoCount = self.pause_demoCount self.demoCounter = self.demoCount - 1 + + # INITIATE A NEW TREATMENT SETUP ---------------------------------- elif msg_id == MsgIds.MSG_ID_UI_INITIATE_TREATMENT_REQUEST.value: rsp_id = MsgIds.MSG_ID_HD_OP_MODE if params.data_int[0] == EResponse.Accepted: @@ -292,31 +301,39 @@ elif msg_id == MsgIds.MSG_ID_UI_NEW_TREATMENT_PARAMS.value: rsp_id = MsgIds.MSG_ID_HD_NEW_TREATMENT_PARAMS_RESPONSE - rsp_payload = struct.pack("<" + str(self.NUM_TREATMENT_PARAMETERS) + "i", + rsp_payload = struct.pack("<" + str(TreatmentParameters.NUM_OF_TREATMENT_PARAMS.value + 1) + "i", 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) - self.demo_treatment_params = deepcopy(params) + self.demo_treatment_params = deepcopy(params) # keep a complete copy + # UF Treatment + self.treatment_time_sec = params.data_int[TreatmentParameters.TREATMENT_PARAM_TREATMENT_DURATION_MIN.value] * 60 + self.uf_volume_set_l = 0 # TBD not in this message + self.uf_volume_out_l = 0 # reset status + self.uf_rate_l_per_sec = 0 + self.salineVolume_ml = 0.0 # status + self.salineVolCum_ml = 0.0 # status + # Rinseback + self.rinseback_volume_set_ml = 80 + 120 # TBD! 80 + should be based on dialyzer blood volume? + self.rinsebackVelocity_ml_per_sec = params.data_int[TreatmentParameters.TREATMENT_PARAM_RINSEBACK_FLOW_RATE_ML_MIN.value] / 60.0 + self.rinseback_volume_out_ml = 0 # reset status + self.rinseback_volume_all_ml = 0 + # Heparin + self.hep_stop_min = params.data_int[TreatmentParameters.TREATMENT_PARAM_HEPARIN_PRESTOP_MIN.value] + self.hep_rate_ml_per_hr = params.data_float[TreatmentParameters.TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR.value] + self.hep_bolus_ml = params.data_float[TreatmentParameters.TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML.value] + self.hep_out_ml = 0 # reset status # 'Secret' speed setting: 10x heparin bolus volume, when heparinStopTime=430 and heparinRate is OFF - sto = params.data_int[TreatmentParameters.TREATMENT_PARAM_HEPARIN_PRESTOP_MIN.value] - hdr = params.data_float[TreatmentParameters.TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR.value] - hbv = params.data_float[TreatmentParameters.TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML.value] # if math.isclose(sto, 430) and math.isclose(hdr, 0) and (hbv > 0.199): # self.demoSpeed = int(hbv * 10 + 0.5) # else: # self.demoSpeed = 1 - self.treatment_time_sec = params.data_int[TreatmentParameters.TREATMENT_PARAM_TREATMENT_DURATION_MIN.value] * 60 - self.uf_volume_set_l = params.data_int[TreatmentParameters.TREATMENT_PARAM_UF_VOLUME_L.value] - self.rinsebackVolume_mL = 250.0 # TBD! should be based on dialyzer blood volume - self.rinsebackVelocity_mL_per_sec = params.data_int[TreatmentParameters.TREATMENT_PARAM_RINSEBACK_FLOW_RATE_ML_MIN.value] / 60.0 - - elif msg_id == MsgIds.MSG_ID_UI_USER_CONFIRM_TREATMENT_PARAMS.value: if params.data_int[0] == EResponse.Accepted: ## TBD!!! FOLLOWING IS FUTILE ATTEMPT TO SET UF MAX - calc_max_uf_volume = min(int(self.MAX_UF_RATE_ML_PER_SEC * self.treatment_time_sec/100)*100, self.MAX_UF_ML_PER_TX) + calc_max_uf_volume = min(int(self.MAX_UF_RATE_ML_PER_SEC * self.treatment_time_sec/100.0)*100.0, self.MAX_UF_ML_PER_TX) self.cmd_set_treatment_parameter_ranges(min_treatment_duration=0, max_treatment_duration=480, min_uf_volume=0.0, max_uf_volume=calc_max_uf_volume, @@ -328,8 +345,8 @@ ## TBD!! Is this needed to clear UI from presenting old data? self.cmd_set_treatment_saline_bolus_data(target=self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML.value], cumulative=0.0, delivered=0.0) - self.salineVolume_mL = 0.0 - self.salineVolCum_mL = 0.0 + self.salineVolume_ml = 0.0 + self.salineVolCum_ml = 0.0 rsp_id = MsgIds.MSG_ID_PRE_TREATMENT_STATE rsp_payload = struct.pack( "<" + str(PreTreatmentSubModes.NUM_OF_HD_PRE_TREATMENT_STATES.value + 1) + "i", @@ -354,6 +371,7 @@ rsp_payload = integer_to_bytearray(EResponse.Rejected) rsp_payload += integer_to_bytearray(0) + # WATER SAMPLING -------------------------------------------------- elif msg_id == MsgIds.MSG_ID_UI_SAMPLE_WATER_RESULT.value: # sample water completed, prime filter... if params.data_int[0] == EResponse.Accepted: self.demoTimedIncValue = PreTreatmentConsumableSelfTestStates.CONSUMABLE_SELF_TESTS_INSTALL_STATE.value @@ -392,6 +410,7 @@ ) self.demoSelection = 0 # Wait for user + # PRETREATMENT INSTALL AND TESTS --------------------------------- elif msg_id == MsgIds.MSG_ID_UI_CONSUMABLE_INSTALL_CONFIRM.value: # assuming everything is setup in preceding MSG_ID_UI_SAMPLE_WATER_RESULT handling self.demoSelection = 6 # TBD setup event to change to @@ -414,10 +433,11 @@ elif msg_id == MsgIds.MSG_ID_UI_START_PRIME_REQUEST.value: # _60 x3C 'Start Prime' self.demoSelection = 10 # continue on, picking up from previous state setup by selection 9 self.demoCount = 5 - # self.demoCounter = self.demoCount # TBD! creates illusion of starting + self.demoCounter = self.demoCount # TBD! creates illusion of starting self.demoGroupCount = 12 * self.demoCount # aggregate counter self.demoGroupCounter = 0 # aggregate counter TBD SHOULD be handled by previous group end logic (?) + # TREATMENT: PATIENT CONNECT -------------------------------------- elif msg_id == MsgIds.MSG_ID_UI_PATIENT_CONNECTION_BEGIN_REQUEST.value: # 100 x64 'Continue' Priming Complete # TBD!!! Setup UF Range before this rsp_id = MsgIds.MSG_ID_PRE_TREATMENT_STATE @@ -436,22 +456,25 @@ ) self.demoSelection = 0 # Wait for user - elif msg_id == MsgIds.MSG_ID_UI_SET_UF_VOLUME_PARAMETER.value: # _79 x4F + elif msg_id == MsgIds.MSG_ID_UI_SET_UF_VOLUME_PARAMETER.value: # _79 x4F rsp_id = MsgIds.MSG_ID_HD_SET_UF_VOLUME_PARAMETER_RESPONSE rsp_payload = integer_to_bytearray(EResponse.Accepted) rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) rsp_payload += integer_to_bytearray(params.data_int[0]) # echo back setting - self.uf_volume_set_l = params.data_float[0] / 1000.0 # TBD!! passed as mL - self.uf_rate_l_per_sec = self.uf_volume_set_l / (self.treatment_time_sec - self.uf_stop_time_sec) + self.uf_volume_set_l = params.data_float[0] / 1000.0 # TBD!! passed as mL instead + if (self.uf_volume_set_l is not None) and (self.uf_volume_set_l >= 0.0009 ) and (self.uf_stop_time_sec is not None): + self.uf_rate_l_per_sec = self.uf_volume_set_l / (self.treatment_time_sec - self.uf_stop_time_sec) # param + else: + self.uf_rate_l_per_sec = 0 self.demoSelection = 0 # Wait for user - elif msg_id == MsgIds.MSG_ID_UI_PATIENT_CONNECTION_CONFIRM.value: # 102 x66 + elif msg_id == MsgIds.MSG_ID_UI_PATIENT_CONNECTION_CONFIRM.value: # 102 x66 rsp_id = MsgIds.MSG_ID_HD_PATIENT_CONNECTION_CONFIRM_RESPONSE rsp_payload = integer_to_bytearray(EResponse.Accepted) rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) self.demoSelection = 0 # Wait for user - elif msg_id == MsgIds.MSG_ID_UI_START_TREATMENT_REQUEST.value: # 113 x71 + elif msg_id == MsgIds.MSG_ID_UI_START_TREATMENT_REQUEST.value: # 113 x71 rsp_id = MsgIds.MSG_ID_HD_START_TREATMENT_RESPONSE rsp_payload = integer_to_bytearray(EResponse.Accepted) rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) @@ -461,7 +484,7 @@ elif msg_id == MsgIds.MSG_ID_USER_TREATMENT_TIME_CHANGE_REQUEST.value: # _22 x16 rsp_id = MsgIds.MSG_ID_USER_TREATMENT_TIME_CHANGE_RESPONSE if params.data_int[0] is not None: - if params.data_int[0] == 4 * 60 + 30: + if params.data_int[0] == 4 * 60 + 30: # 'secret' means to force end if 0 duration is unavailable params.data_int[0] = 0 self.treatment_time_sec = params.data_int[0] * 60 rsp_payload = integer_to_bytearray(EResponse.Accepted) @@ -481,30 +504,44 @@ else: self.demoSelection = 33 # Bolus Stop request - elif msg_id == MsgIds.MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST.value: ## TBD! _70 x46? + elif msg_id == MsgIds.MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST.value: # _70 x46 rsp_id = MsgIds.MSG_ID_HD_PRESSURE_LIMITS_CHANGE_RESPONSE rsp_payload = integer_to_bytearray(EResponse.Accepted) rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) - pass ## TBD! _70 x46? handle update: 4 params + # apply new settings + self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_LOW_LIMIT_MMHG.value] =\ + params.data_int[0] + self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_HIGH_LIMIT_MMHG.value] =\ + params.data_int[1] + self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_LOW_LIMIT_MMHG.value] =\ + params.data_int[2] + self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_HIGH_LIMIT_MMHG.value] =\ + params.data_int[3] + rsp_payload += integer_to_bytearray(params.data_int[0]) # reply with as set + rsp_payload += integer_to_bytearray(params.data_int[1]) + rsp_payload += integer_to_bytearray(params.data_int[2]) + rsp_payload += integer_to_bytearray(params.data_int[3]) elif msg_id == MsgIds.MSG_ID_UI_RINSEBACK_CMD.value: # _82 x52 rsp_id = MsgIds.MSG_ID_HD_RINSEBACK_CMD_RESPONSE rsp_payload = integer_to_bytearray(EResponse.Accepted) rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) if params.data_int[0] ==0: # 0 Start Rinseback + self.rinseback_volume_out_ml = 0 # reset these self.demoSelection = 41 - elif params.data_int[0] == 1: # 1 Accelerate - self.rinsebackVelocity_mL_per_sec += 15.0 /60.0 # ++15 mL/min - pass # Accelerate - elif params.data_int[0] == 2: # 2 Decelerate - self.rinsebackVelocity_mL_per_sec -= 15.0 /60.0 # --15 mL/min - pass # + elif params.data_int[0] == 1: # 1 Accelerate ++25 mL/min (R) + self.rinsebackVelocity_ml_per_sec = min( self.rinsebackVelocity_ml_per_sec + 25.0 / 60.0, + self.rinsebackVelocity_max_ml_per_sec ) + elif params.data_int[0] == 2: # 2 Decelerate --25 mL/min (R) + self.rinsebackVelocity_ml_per_sec = max( self.rinsebackVelocity_ml_per_sec - 25.0 / 60.0, + self.rinsebackVelocity_min_ml_per_sec ) elif params.data_int[0] == 3: # 3 Pause self.demoSelection = 44 - TreatmentRinsebackStates.RINSEBACK_PAUSED_STATE.value # TBD!! + elif params.data_int[0] == 4: # 4 Resume + self.demoSelection = 41 - elif params.data_int[0] == 99: # TBD!! Additional - self.rinseback_volume_set_mL += 50.0 # ++50 mL + elif params.data_int[0] == 6: # TBD!! Additional + self.rinseback_volume_set_ml += 10.0 # ++10 mL (R) TreatmentRinsebackStates.RINSEBACK_RUN_ADDITIONAL_STATE.value #TBD!! # 4 Additional rinseback volume (10 mL) state of the rinseback sub-mode state machine self.demoSelection = 41 @@ -515,20 +552,60 @@ rsp_payload += integer_to_bytearray(0) self.demoSelection = 0 # Complete Treatment self.demoCount = 0 # immediately - elif params.data_int[0] == 9: pass # TBD!! Additional 9 = return to treatment - elif msg_id == MsgIds.MSG_ID_UI_PATIENT_DISCONNECTION_CONFIRM.value: - pass ## TBD! + elif params.data_int[0] == 9: # TBD!! Additional not implemented 9 = return to treatment + rsp_payload = integer_to_bytearray(EResponse.Rejected) - elif msg_id == MsgIds.MSG_ID_UI_DISPOSABLE_REMOVAL_CONFIRM.value: + elif msg_id == MsgIds.MSG_ID_UI_PATIENT_DISCONNECTION_CONFIRM.value or \ + msg_id == MsgIds.MSG_ID_UI_TREATMENT_LOG_DATA_REQUEST: # _74 x4A + # rsp_id = MsgIds.MSG_ID_HD_TREATMENT_LOG_DATA_RESPONSE + # self.cmd_send_post_treatment_log_response( + # accepted = EResponse.Accepted, # bool + # reason = RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value, # int, + # bood_flow_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_BLOOD_FLOW_RATE_ML_MIN.value], # int + # dialysate_flow_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_DIALYSATE_FLOW_RATE_ML_MIN.value], # int + # treatment_duration = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_TREATMENT_DURATION_MIN.value], # int + # actual_treatment_duration = int(self.treatment_stop_time_s-self.treatment_start_time_s), # int + # acid_concentrate_type = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_ACID_CONCENTRATE.value], # int + # bicarbonate_concentrate_type = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_BICARB_CONCENTRATE.value], # int + # potassium_concentration = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_.value], # int + # calcium_concentration = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # bicarbonate_concentration = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # sodium_concentration = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # dialysate_temperature = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # dialyzer_type = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # treatment_start_date_time = int(self.treatment_start_time_s), # int + # treatment_end_date_time = int(self.treatment_stop_time_s), # int + # average_blood_flow = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # average_dialysate_flow = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # dialysate_volume_used = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # average_dialysate_temp = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # origin_uf_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # target_uf_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # actual_uf_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # origin_uf_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # target_uf_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # actual_uf_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # saline_bolus_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # heparin_bolus_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # heparin_dispense_rate = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # heparin_pre_stop = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # heparin_delivered_volume = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # heparin_type = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # average_arterial_pressure = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # average_venous_pressure = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # float + # device_id = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # water_sample_test_result = demo_treatment_params.data_int[TreatmentParameters.TREATMENT_.value], # int + # ) pass - # rsp_id = MsgIds.MSG_ID_HD_RINSEBACK_CMD_RESPONSE - # rsp_payload = integer_to_bytearray(EResponse.Accepted) - # rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) - # if params.data_int[0] == 8: # TBD!! need real ID consts - # rsp_id = MsgIds.MSG_ID_HD_OP_MODE - # rsp_payload = integer_to_bytearray(HDOpModes.MODE_POST.value) - # rsp_payload += integer_to_bytearray(0) + + elif msg_id == MsgIds.MSG_ID_UI_DISPOSABLE_REMOVAL_CONFIRM.value: # 115 x73 + rsp_id = MsgIds.MSG_ID_HD_DISPOSABLE_REMOVAL_CONFIRM_RESPONSE + rsp_payload = integer_to_bytearray(EResponse.Accepted) + rsp_payload += integer_to_bytearray(RequestRejectReasons.REQUEST_REJECT_REASON_NONE.value) + self.demoSelection = 50 + self.demoCount = 0 # immediately + # # -------------------------------------------------- # Send Response if needed @@ -541,9 +618,12 @@ self.demoSemaphore.release() def run_demoTimer_timeout(self) -> None: + start_time = time() while self.demoTimer.is_alive(): self.do_demoTimer_timeout() - sleep(1) + elapsed_time = (time()-start_time) + wait_time = 1.0 - (elapsed_time % 1.0) + sleep(wait_time) self.demoTimer.cancel() def do_demoTimer_timeout(self) -> None: @@ -557,15 +637,13 @@ rsp_payload = None rsp_channel_id = DenaliChannels.hd_to_ui_ch_id # default - if self.demoCounter < self.demoCount: + if (self.demoCounter <= self.demoCount) or (self.demoCount < 1): print("t", end='') # TBD - # TBD if self.demoSelection != 0: # don't count when waiting on user TBD? But Need this for screen timing - ctrIncrement = min(self.demoCount - self.demoCounter, self.demoSpeed) + ctrIncrement = max(1, min(self.demoCount - self.demoCounter, self.demoSpeed)) self.demoCounter += ctrIncrement if self.demoGroupCount is not None: self.demoGroupCounter += ctrIncrement - - else: + if self.demoCounter > self.demoCount: print("T", end='') # TBD self.demoCounter = 0 self.demoCountdownId = None @@ -580,6 +658,7 @@ rsp_payload += integer_to_bytearray(HDInitStates.POST_STATE_START.value) self.demoSelection = 2 # setup event to change state on demoTimer self.demoCount = 3 + self.demoGroupCount = None elif self.demoSelection == 2: # TBD Auto transit to standby rsp_id = MsgIds.MSG_ID_HD_OP_MODE @@ -719,7 +798,7 @@ self.demoGroupCount = 12 * 5 # aggregate count up to TBD! cleanup numbers if self.demoTimedIncValue == PreTreatmentPrimeStates.HD_PRIME_WAIT_FOR_USER_START_STATE.value: self.demoSelection = 0 # Wait for User - self.demoGroupCounter = 0 # aggregate counter + # self.demoGroupCounter = 0 # aggregate counter elif self.demoTimedIncValue >= PreTreatmentPrimeStates.NUM_OF_HD_PRIME_STATES.value - 1: self.demoTimedIncValue = None self.demoSelection = 11 @@ -754,7 +833,9 @@ rsp_payload += integer_to_bytearray(0) self.demoCountdownId = MsgIds.MSG_ID_HD_BLOOD_PRIME_PROGRESS self.demoCount = 0 - self.demoGroupCount = int(120 / 8) # TBD! fix const numbers + self.demoCounter = 1 + # self.demoGroupCount = int(120 / 8) # TBD! fix const numbers + # self.demoGroupCount = -1 self.demoSelection = 21 # Initiate Blood Prime elif self.demoSelection == 21: # Blood Prime @@ -774,6 +855,7 @@ self.demoSelection = 22 # Complete Blood Prime -> Dialysis self.demoCountdownId = MsgIds.MSG_ID_HD_BLOOD_PRIME_PROGRESS self.demoCount = int(120 / 8) # TBD! fix const numbers + self.demoCounter = -1 # give slight delay # MSG_ID_PRESSURE_OCCLUSION_DATA ## TBD! combine with Treatment update data self.arterial_pressure_mmHg += (random() - 0.5) * 10 # TBD! replace magic wander numbers @@ -792,9 +874,10 @@ ## DIALYSIS GROUP ------------------------------------------------- elif self.demoSelection == 22: # Dialysis # preset timing info + self.treatment_start_time_s = time() self.cmd_set_treatment_time(sec_total=self.treatment_time_sec, sec_elapsed=0, sec_remain=self.treatment_time_sec) - self.demoCount = self.demoSpeed + self.demoCount = self.demoSpeed - 1 self.demoGroupCount = self.treatment_time_sec #TBD!! replace with user setting self.demoGroupCounter = 0 self.demoSelection = 29 # start dialysis @@ -816,8 +899,9 @@ self.demoSelection = 30 # ongoing data update elif self.demoSelection >= 30 and self.demoSelection < 40 : # Dialysis Data Update ---------------- + self.blood_stop_time_s = time() # reset timer + self.treatment_stop_time_s = self.blood_stop_time_s - # MSG_ID_BLOOD_FLOW_DATA self.blood_flow_measured_ml_per_min += (random() - 0.5) * 10 # TBD! replace magic numbers if self.blood_flow_measured_ml_per_min > (self.blood_flow_set_point_ml_per_min + 30): @@ -859,19 +943,19 @@ # MSG_ID_DIALYSATE_OUT_FLOW_DATA # TBD!! parameters seem swapped and off by 1000x ?? # self.cmd_set_treatment_ultrafiltration_outlet_flow_data(ref_uf_vol=self.uf_volume_set_l, - # measured_uf_vol=self.uf_volume_l, + # measured_uf_vol=self.uf_volume_out_l, # rot_speed=0.0, mot_speed=0.0, mc_speed=0.0, # mc_current=0.0, pwm=0.0) - self.uf_volume_l = min(self.uf_volume_l + self.uf_rate_l_per_sec, self.uf_volume_set_l) - self.cmd_set_treatment_ultrafiltration_outlet_flow_data(ref_uf_vol=self.uf_volume_l * 1000.0, + self.uf_volume_out_l = min(self.uf_volume_out_l + self.uf_rate_l_per_sec, self.uf_volume_set_l) + self.cmd_set_treatment_ultrafiltration_outlet_flow_data(ref_uf_vol=self.uf_volume_out_l * 1000.0, measured_uf_vol=self.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) # MSG_ID_LOAD_CELL_READINGS # MSG_ID_TREATMENT_TIME - if self.treatment_time_sec != self.demoGroupCount: + if self.treatment_time_sec != self.demoGroupCount: # handle user change in treatment time self.demoGroupCount = max(self.treatment_time_sec, self.demoGroupCounter) ctr_elapsed_sec = min(self.demoGroupCounter, self.demoGroupCount) @@ -880,9 +964,12 @@ self.cmd_set_treatment_time(sec_total=self.demoGroupCount, sec_elapsed=ctr_elapsed_sec, sec_remain=ctr_remain_sec) + self.demoGroupCounter -= 1 # TBD! effectively freeze countdown MAYBE? + # sub selections within Dialysis Data Update if self.demoSelection == 30: # Standard UF Dialysis . . . . . . . . . . - if self.demoGroupCounter >= self.demoGroupCount: + self.demoGroupCounter += 1 # TBD! effectively unfreeze countdown MAYBE? + if self.demoGroupCounter >= self.demoGroupCount: # end of Treatment self.demoGroupCount = None self.demoGroupCounter = 0 self.demoSelection = 40 @@ -902,139 +989,106 @@ 0, # 9 Dialysis state ) self.demoSelection = 32 - self.salineVolume_mL = 0.0 # reset + self.salineVolume_ml = 0.0 # reset elif self.demoSelection == 32: # Saline Bolus delivery rsp_id = MsgIds.MSG_ID_SALINE_BOLUS_DATA bolus_target_ml = self.demo_treatment_params.data_int[TreatmentParameters.TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML.value] - new_volume_ml = bolus_target_ml - self.salineVolume_mL - if 8.0 <= new_volume_ml: - new_volume_ml = 8.0 # incremental + new_volume_ml = bolus_target_ml - self.salineVolume_ml + if self.salineBolusRate_mlpersec <= new_volume_ml: + new_volume_ml = self.salineBolusRate_mlpersec # incremental else: self.demoSelection = 33 # done after this, so move on - self.salineVolume_mL += new_volume_ml - self.salineVolCum_mL += new_volume_ml + self.salineVolume_ml += new_volume_ml + self.salineVolCum_ml += new_volume_ml rsp_payload = struct.pack("= 40) and (self.demoSelection < 50): + set_rinseback_state = None + new_volume_ml = self.rinsebackVelocity_ml_per_sec # incremental + self.demoCount = 0 + self.demoGroupCount = None # int(self.rinseback_volume_set_ml / self.rinsebackVelocity_ml_per_sec + 0.99) + self.demoCountdownId = None - elif self.demoSelection == 41: # Rinseback running - rsp_id = MsgIds.MSG_ID_TREATMENT_STATE - rsp_payload = struct.pack("<10i", - TreatmentStates.TREATMENT_RINSEBACK_STATE.value, # 0 Treatment Submode - TreatmentDialysisStates.DIALYSIS_UF_STATE.value, # 1 UF state - 0, # 2 Saline bolus state - 0, # 3 Hep state - TreatmentRinsebackStates.RINSEBACK_RUN_STATE.value, # 4 Rinseback state - 0, # 5 Recirc state - 0, # 6 Blood Prime state - 0, # 7 End state - 0, # 8 Stop state - 0, # 9 Dialysis state - ) - self.demoCount = 1 ##TBD self.demoGroupCount - self.demoSelection = 42 # next state + if self.demoSelection == 40: # Rinseback stop before + set_rinseback_state = TreatmentRinsebackStates.RINSEBACK_STOP_INIT_STATE + self.rinseback_volume_out_ml = 0 + self.demoSelection = 49 # then wait for user - elif self.demoSelection == 42: # Rinseback in process + elif self.demoSelection == 41: # Rinseback running + set_rinseback_state = TreatmentRinsebackStates.RINSEBACK_RUN_STATE + self.demoSelection = 42 # next state + + elif self.demoSelection == 42: # Rinseback in process + remain_volume_ml = self.rinseback_volume_set_ml - self.rinseback_volume_out_ml + if remain_volume_ml <= new_volume_ml: + new_volume_ml = remain_volume_ml + self.demoSelection = 43 # done after this, so move on + self.rinseback_volume_out_ml += new_volume_ml + self.rinseback_volume_all_ml += new_volume_ml + + elif self.demoSelection == 43: # Rinseback stop after + set_rinseback_state = TreatmentRinsebackStates.RINSEBACK_STOP_STATE + self.demoSelection = 49 + + elif self.demoSelection == 44: # Rinseback pause + set_rinseback_state = TreatmentRinsebackStates.RINSEBACK_PAUSED_STATE + self.demoSelection = 49 + + elif self.demoSelection == 49: # Rinseback wait for user + pass + + # for all Rinseback states: + if self.demoSelection <= 42: # actively/recently moving blood + self.blood_stop_time_s = time() # reset timer + rsp_id = MsgIds.MSG_ID_HD_RINSEBACK_PROGRESS - rb_target_ml = self.rinseback_volume_set_ml - new_volume_ml = rb_target_ml - self.rinseback_volume_out_ml - if rinsebackVelocity_mL_per_sec <= new_volume_ml: - new_volume_ml = rinsebackVelocity_mL_per_sec # incremental - else: - self.demoSelection = 43 # done after this, so move on - self.rinseback_volume_out_ml += new_volume_ml - self.rinseback_volume_all_ml += new_volume_ml - rsp_payload = struct.pack(" None: @@ -2004,14 +2046,15 @@ @return: none """ self.cmd_set_treatment_states_data(TXStates.TREATMENT_DIALYSIS_STATE, - TXStates.UF_OFF_STATE, + TXStates.UF_OFF_STATE, # TBD this & follows are Submodes not States as expecte TXStates.SALINE_BOLUS_STATE_IDLE, TXStates.HEPARIN_STATE_OFF, TXStates.RINSEBACK_STOP_INIT_STATE, TXStates.TREATMENT_RECIRC_RECIRC_STATE, TXStates.BLOOD_PRIME_RAMP_STATE, TXStates.TREATMENT_END_WAIT_FOR_RINSEBACK_STATE, - TXStates.TREATMENT_STOP_RECIRC_STATE) + TXStates.TREATMENT_STOP_RECIRC_STATE, + TXStates.TREATMENT_DIALYSIS_STATE) def cmd_set_hd_operation_mode_data(self, operation_mode: int, operation_sub_mode: int) -> None: """ @@ -2391,7 +2434,7 @@ """ self.logger.debug("Handling request for hd version.") - self.cmd_send_version_hd_data(9, 9, 9, 9, 9, 9, 9, 9) + self.cmd_send_version_hd_data(9, 9, 9, 9, 9, 9, 9, 9, 9) self.cmd_send_hd_serial_number() def cmd_send_hd_serial_number(self) -> None: @@ -2646,7 +2689,7 @@ self.can_interface.send(message, 0) def cmd_send_post_treatment_log_response(self, accepted: bool, reason: int, - bood_flow_rate: int, + blood_flow_rate: int, dialysate_flow_rate: int, treatment_duration: int, actual_treatment_duration: int, @@ -2683,9 +2726,9 @@ ) -> None: """ send post treatment log response - @param accepted: true if accpeted + @param accepted: true if accepted @param reason: the rejection reason - @param bood_flow_rate: bood flow rate + @param blood_flow_rate: blood flow rate @param dialysate_flow_rate: dialysate flow rate @param treatment_duration: treatment duration @param actual_treatment_duration: actual treatment duration @@ -2724,7 +2767,7 @@ payload = integer_to_bytearray(accepted) payload += integer_to_bytearray(reason) - payload += unsigned_integer_to_bytearray(int(bood_flow_rate)) + payload += unsigned_integer_to_bytearray(int(blood_flow_rate)) payload += unsigned_integer_to_bytearray(int(dialysate_flow_rate)) payload += unsigned_integer_to_bytearray(int(treatment_duration)) payload += unsigned_integer_to_bytearray(int(actual_treatment_duration))