########################################################################### # # Copyright (c) 2019-2020 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 ui_proxy.py # # @author (last) Peter Lucia # @date (last) 28-Aug-2020 # @author (original) Sean # @date (original) 15-Apr-2020 # ############################################################################ from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray, float_to_bytearray import struct import enum from ..utils.base import _AbstractSubSystem, _publish from ..common.msg_defs import MsgIds, RequestRejectReasons, MsgFldPositions from collections import OrderedDict from logging import Logger class HDUIProxy(_AbstractSubSystem): """ Hemodialysis Delivery (HD) Dialin API sub-class for ui commands. """ LITER_TO_ML_CONVERSION_FACTOR = 1000.0 # UF pause/resume command IDs UF_CMD_PAUSE = 0 UF_CMD_RESUME = 1 # UF change option IDs UF_CMD_CHANGE_TIME_TO_ADJUST = 0 UF_CMD_CHANGE_RATE_TO_ADJUST = 1 # in-treatment change response codes RESPONSE_REJECTED = 0 RESPONSE_ACCEPTED = 1 # start treatment command IDs START_TREATMENT_CMD_INITIATE_TREATMENT_WORKFLOW = 0 START_TREATMENT_CMD_CANCEL_TREATMENT_WORKFLOW = 1 START_TREATMENT_CMD_START_TREATMENT = 2 # HD version message field positions START_POS_MAJOR = DenaliMessage.PAYLOAD_START_INDEX END_POS_MAJOR = START_POS_MAJOR + 1 START_POS_MINOR = END_POS_MAJOR END_POS_MINOR = START_POS_MINOR + 1 START_POS_MICRO = END_POS_MINOR END_POS_MICRO = START_POS_MICRO + 1 START_POS_BUILD = END_POS_MICRO END_POS_BUILD = START_POS_BUILD + 2 # FPGA START_POS_FPGA_ID = END_POS_BUILD END_POS_FPGA_ID = START_POS_FPGA_ID + 1 START_POS_FPGA_MAJOR = END_POS_FPGA_ID END_POS_FPGA_MAJOR = START_POS_FPGA_MAJOR + 1 START_POS_FPGA_MINOR = END_POS_FPGA_MAJOR END_POS_FPGA_MINOR = START_POS_FPGA_MINOR + 1 START_POS_FPGA_LAB = END_POS_FPGA_MINOR END_POS_FPGA_LAB = START_POS_FPGA_LAB + 1 class TreatmentParameters(enum.Enum): TREATMENT_PARAM_BLOOD_FLOW_RATE_ML_MIN = 0 TREATMENT_PARAM_DIALYSATE_FLOW_RATE_ML_MIN = 1 TREATMENT_PARAM_TREATMENT_DURATION_MIN = 2 TREATMENT_PARAM_HEPARIN_PRESTOP_MIN = 3 TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML = 4 TREATMENT_PARAM_ACID_CONCENTRATE = 5 TREATMENT_PARAM_BICARB_CONCENTRATE = 6 TREATMENT_PARAM_DIALYZER_TYPE = 7 TREATMENT_PARAM_BLOOD_PRESSURE_MEAS_INTERVAL_MIN = 8 TREATMENT_PARAM_RINSEBACK_FLOW_RATE_ML_MIN = 9 TREATMENT_PARAM_ARTERIAL_PRESSURE_LOW_LIMIT_MMHG = 10 TREATMENT_PARAM_ARTERIAL_PRESSURE_HIGH_LIMIT_MMHG = 11 TREATMENT_PARAM_VENOUS_PRESSURE_LOW_LIMIT_MMHG = 12 TREATMENT_PARAM_VENOUS_PRESSURE_HIGH_LIMIT_MMHG = 13 TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR = 14 TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML = 15 TREATMENT_PARAM_DIALYSATE_TEMPERATURE_C = 16 TREATMENT_PARAM_UF_VOLUME_L = 17 NUM_OF_TREATMENT_PARAMS = 18 @classmethod def has_value(cls, value): return value in cls._value2member_map_ def __init__(self, can_interface, logger: Logger): """ @param can_interface: the denali can interface object """ super().__init__() self.can_interface = can_interface self.logger = logger # register function to handle HD response to UF change requests if self.can_interface is not None: channel_id = DenaliChannels.hd_to_ui_ch_id self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_USER_UF_SETTINGS_CHANGE_RESPONSE.value, self._handler_uf_change_response) self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_USER_UF_SETTINGS_CHANGE_CONFIRMATION_RESPONSE.value, self._handler_uf_change_confirm_response) self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_USER_TREATMENT_TIME_CHANGE_RESPONSE.value, self._handler_treatment_duration_change_response) self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_USER_BLOOD_DIAL_RATE_CHANGE_RESPONSE.value, self._handler_blood_and_dialysate_change_response) self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_TREATMENT_PARAM_CHANGE_RANGES.value, self._handler_treatment_param_ranges) self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_VERSION.value, self._handler_hd_version) self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_UI_NEW_TREATMENT_PARAMS.value, self._handler_treatment_param_settings) self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_NEW_TREATMENT_PARAMS_RESPONSE.value, self._handler_treatment_param_settings_response) self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_USER_SALINE_BOLUS_RESPONSE.value, self._handler_saline_bolus_response) # initialize variables that will be populated by HD version response self.hd_version = None self.fpga_version = None # initialize treatment parameters that are seen from UI or that Dialin user sets self.treatment_parameters = [0.0] * self.TreatmentParameters.NUM_OF_TREATMENT_PARAMS.value # initialize variables that will be populated by treatment parameters response message self.treatment_parameters_valid = False self.treatment_parameters_reject_reasons = [0] * self.TreatmentParameters.NUM_OF_TREATMENT_PARAMS.value # initialize variables that will be populated by treatment parameter ranges message self.min_treatment_duration_min = 0 self.max_treatment_duration_min = 0 self.min_uf_volume_ml = 0.0 self.max_uf_volume_ml = 0.0 self.min_dialysate_flow_rate_ml_min = 0 self.max_dialysate_flow_rate_ml_min = 0 # initialize variables that will be populated by response from HD to treatment duration change request self.duration_change_succeeded = False self.duration_change_reject_reason = 0 self.duration_change_time_min = 0 self.duration_change_uf_vol_ml = 0 # initialize variables that will be populated by response from HD to UF change request self.uf_change_succeeded = False self.uf_change_reject_reason = 0 self.uf_change_volume_ml = 0.0 self.uf_change_time_min = 0 self.uf_change_rate_ml_min = 0.0 self.uf_change_time_diff = 0 self.uf_change_rate_diff = 0.0 self.uf_old_rate_ml_min = 0.0 # initialize variables that will be populated by response from HD to blood & dialysate flow rate change request self.blood_and_dialysate_flow_rate_change_succeeded = False self.blood_and_dialysate_flow_rate_change_reject_reason = 0 self.target_blood_flow_rate = 0 self.target_dialysate_flow_rate = 0 # initialize variables that will be populated by response to saline bolus request self.saline_bolus_request_succeeded = False self.saline_bolus_request_reject_reason = 0 self.saline_bolus_request_bolus_volume = 0 self.reject_reasons = OrderedDict() for attr in dir(self): if not callable(getattr(self, attr)) and attr.startswith("REQUEST_REJECT"): self.reject_reasons[attr] = getattr(self, attr) self.reject_reasons = OrderedDict(sorted(self.reject_reasons.items(), key=lambda key: key[1])) def get_hd_version(self): """ Gets the hd version @return: The hd version """ return self.hd_version def get_fpga_version(self): """ Gets the fpga version @return: the fpga version """ return self.fpga_version def get_treatment_parameters(self): """ Gets the array of treatment parameters set by user or Dialin @return: the array of treatment parameters """ return self.treatment_parameters def get_min_treatment_duration_min(self): """ Gets the min treatment duration @return: the min treatment duration (minutes) """ return self.min_treatment_duration_min def get_max_treatment_duration_min(self): """ Gets the max treatment duration @return: The max treatment duration (minutes) """ return self.max_treatment_duration_min def get_min_uf_volume_ml(self): """ Gets the min uf volume @return: the min uf volume (mL) """ return self.min_uf_volume_ml def get_max_uf_volume_ml(self): """ Gets the max uf volume @return: The max uf volume (mL) """ return self.max_uf_volume_ml def get_min_dialysate_flow_rate_ml_min(self): """ Gets the min dialysate flow rate @return: The min dialysate flow rate (mL/min) """ return self.min_dialysate_flow_rate_ml_min def get_max_dialysate_flow_rate_ml_min(self): """ Gets the max dialysate flow rate @return: The max dialysate flow rate (mL/min) """ return self.max_dialysate_flow_rate_ml_min def get_duration_change_succeeded(self): """ Gets the duration change succeeded status @return: (bool) The duration change succeeded status """ return self.duration_change_succeeded def get_duration_change_reject_reason(self): """ Gets the duration change reject reason @return: (int) The duration change reject reason """ return self.duration_change_reject_reason def get_reject_reasons(self): """ Gets all possible reject reasons @return: OrderedDict(), {"": ... } """ return self.reject_reasons def get_duration_change_time_min(self): """ Gets the duration change time @return: the duration change time (min) """ return self.duration_change_time_min def get_duration_change_uf_vol_ml(self): """ Gets the duration change uf vol @return: the duration change uf vol (mL) """ return self.duration_change_uf_vol_ml def get_uf_change_succeeded(self): """ Gets the uf change succeeded status @return: True if succeeded, False otherwise """ return self.uf_change_succeeded def get_uf_change_reject_reason(self): """ Gets the uf change reject reason @return: (int) The uf change reject reason """ return self.uf_change_reject_reason def get_uf_change_volume_ml(self): """ Gets the uf change volume @return: The uf change volume (mL) """ return self.uf_change_volume_ml def get_uf_change_time_min(self): """ Gets the uf change time @return: The uf change time (min) """ return self.uf_change_time_min def get_uf_change_rate_ml_min(self): """ Gets the uf change rate @return: The uf change rate (mL/min) """ return self.uf_change_rate_ml_min def get_uf_change_time_diff(self): """ Gets the uf change time diff @return: The uf change time diff """ return self.uf_change_time_diff def get_uf_change_rate_diff(self): """ Gets the uf change rate diff @return: The uf change rate diff """ return self.uf_change_rate_diff def get_blood_and_dialysate_flow_rate_change_succeeded(self): """ Gets the blood and dialysate flow rate change succeeded status @return: True if successful, False otherwise """ return self.blood_and_dialysate_flow_rate_change_succeeded def get_blood_and_dialysate_flow_rate_change_reject_reason(self): """ Gets the blood and dialysate flow rate change reject reason @return: (int) The reason for the rejection """ return self.blood_and_dialysate_flow_rate_change_reject_reason def get_target_blood_flow_rate(self): """ Gets the target blood flow rate @return: The target blood flow rate """ return self.target_blood_flow_rate def get_target_dialysate_flow_rate(self): """ Gets the target dialysate flow rate @return: The target dialysate flow rate """ return self.target_dialysate_flow_rate def get_treatment_parameters_valid(self): """ Gets the T/F flag for whether treatment parameters are considered valid by HD. @return: True if treatment parameters are valid, False if not """ return self.treatment_parameters_valid def get_treatment_parameters_reject_reasons(self): """ Gets the reject reason codes for the treatment parameters sent to the HD for validation. @return: The array of reject reason codes for all treatment parameters """ return self.treatment_parameters_reject_reasons def get_blood_flow_rate_reject_reason(self): """ Gets the reject reason code for the blood flow rate treatment parameter. @return: The reject reason code for the blood flow rate """ return self.blood_flow_rate_reject_reason def get_dialysate_flow_rate_reject_reason(self): """ Gets the reject reason code for the dialysate flow rate treatment parameter. @return: The reject reason code for the dialysate flow rate """ return self.dialysate_flow_rate_reject_reason def get_treatment_duration_reject_reason(self): """ Gets the reject reason code for the treatment duration treatment parameter. @return: The reject reason code for the treatment duration """ return self.treatment_duration_reject_reason def get_heparin_pre_stop_time_reject_reason(self): """ Gets the reject reason code for the Heparin pre-stop time treatment parameter. @return: The reject reason code for the Heparin pre-stop time """ return self.heparin_pre_stop_time_reject_reason def get_saline_bolus_volume_reject_reason(self): """ Gets the reject reason code for the saline bolus volume treatment parameter. @return: The reject reason code for the saline bolus volume """ return self.saline_bolus_volume_reject_reason def get_acid_concentrate_reject_reason(self): """ Gets the reject reason code for the acid concentrate treatment parameter. @return: The reject reason code for the acid concentrate """ return self.acid_concentrate_reject_reason def get_bicarb_concentrate_reject_reason(self): """ Gets the reject reason code for the bicarbonate concentrate treatment parameter. @return: The reject reason code for the bicarbonate concentrate """ return self.bicarb_concentrate_reject_reason def get_dialyzer_type_reject_reason(self): """ Gets the reject reason code for the dialyzer type treatment parameter. @return: The reject reason code for the dialyzer type """ return self.dialyzer_type_reject_reason def get_blood_pressure_meas_interval_reject_reason(self): """ Gets the reject reason code for the BP measurement interval treatment parameter. @return: The reject reason code for the BP measurement interval """ return self.blood_pressure_meas_interval_reject_reason def get_rinseback_flow_rate_reject_reason(self): """ Gets the reject reason code for the rinseback flow rate treatment parameter. @return: The reject reason code for the rinseback flow rate """ return self.rinseback_flow_rate_reject_reason def get_arterial_pressure_low_alarm_limit_reject_reason(self): """ Gets the reject reason code for the arterial pressure low alarm limit treatment parameter. @return: The reject reason code for the arterial pressure low alarm limit """ return self.arterial_pressure_low_alarm_limit_reject_reason def get_arterial_pressure_high_alarm_limit_reject_reason(self): """ Gets the reject reason code for the arterial pressure high alarm limit treatment parameter. @return: The reject reason code for the arterial pressure high alarm limit """ return self.arterial_pressure_high_alarm_limit_reject_reason def get_venous_pressure_low_alarm_limit_reject_reason(self): """ Gets the reject reason code for the venous pressure low alarm limit treatment parameter. @return: The reject reason code for the venous pressure low alarm limit """ return self.venous_pressure_low_alarm_limit_reject_reason def get_venous_pressure_high_alarm_limit_reject_reason(self): """ Gets the reject reason code for the venous pressure high alarm limit treatment parameter. @return: The reject reason code for the venous pressure high alarm limit """ return self.venous_pressure_high_alarm_limit_reject_reason def get_heparin_dispense_rate_reject_reason(self): """ Gets the reject reason code for the Heparin dispense rate treatment parameter. @return: The reject reason code for the Heparin dispense rate """ return self.heparin_dispense_rate_reject_reason def get_heparin_bolus_volume_reject_reason(self): """ Gets the reject reason code for the Heparin bolus volume treatment parameter. @return: The reject reason code for the Heparin bolus volume """ return self.heparin_bolus_volume_reject_reason def get_dialysate_temperature_reject_reason(self): """ Gets the reject reason code for the dialysate temperature treatment parameter. @return: The reject reason code for dialysate temperature """ return self.dialysate_temperature_reject_reason def get_saline_bolus_reject_reason(self): """ Gets the reject reason code for the saline bolus request @return: The reject reason code for saline bolus request """ return self.saline_bolus_request_reject_reason def get_saline_bolus_volume(self): """ Gets the HD f/w saline bolus volume (in mL) @return: The saline bolus volume (in mL) """ return self.saline_bolus_request_bolus_volume @_publish([ "hd_version" "fpga_version" ]) def _handler_hd_version(self, message): """ Handler for response from HD regarding its version. @param message: response message from HD regarding valid treatment parameter ranges.\n U08 Major \n U08 Minor \n U08 Micro \n U16 Build \n @return: None if not successful, the version string if unpacked successfully """ major = struct.unpack('B', bytearray( message['message'][self.START_POS_MAJOR:self.END_POS_MAJOR])) minor = struct.unpack('B', bytearray( message['message'][self.START_POS_MINOR:self.END_POS_MINOR])) micro = struct.unpack('B', bytearray( message['message'][self.START_POS_MICRO:self.END_POS_MICRO])) build = struct.unpack('H', bytearray( message['message'][self.START_POS_BUILD:self.END_POS_BUILD])) fpga_id = struct.unpack('B', bytearray( message['message'][self.START_POS_FPGA_ID:self.END_POS_FPGA_ID])) fpga_major = struct.unpack('B', bytearray( message['message'][self.START_POS_FPGA_MAJOR:self.END_POS_FPGA_MAJOR])) fpga_minor = struct.unpack('B', bytearray( message['message'][self.START_POS_FPGA_MINOR:self.END_POS_FPGA_MINOR])) fpga_lab = struct.unpack('B', bytearray( message['message'][self.START_POS_FPGA_LAB:self.END_POS_FPGA_LAB])) if all([len(each) > 0 for each in [major, minor, micro, build]]): self.hd_version = f"v{major[0]}.{minor[0]}.{micro[0]}-{build[0]}" self.logger.debug(f"HD VERSION: {self.hd_version}") if all([len(each) > 0 for each in [fpga_major, fpga_minor, fpga_id, fpga_lab]]): self.fpga_version = f"ID: {fpga_id[0]} v{fpga_major[0]}.{fpga_minor[0]}.{fpga_lab[0]}" self.logger.debug(f"HD FPGA VERSION: {self.fpga_version}") @_publish([ "treatment_parameters" ]) def _handler_treatment_param_settings(self, message): """ Handler for UI msg containing user set treatment parameters. @param message: message from UI to HD containing user selected treatment parameters.\n U32 blood flow rate. \n U32 dialysate flow rate. \n U32 treatment duration. \n U32 Heparin pre-stop time. \n U32 saline bolus volume. \n U32 acid concentrate. \n U32 bicarb concentrate. \n U32 dialyzer type. \n U32 BP measurement interval. \n U32 rinseback flow rate. \n S32 arterial pressure low alarm limit. \n S32 arterial pressure high alarm limit. \n S32 venous pressure low alarm limit. \n S32 venous pressure high alarm limit. \n F32 Heparin dispense rate. \n F32 Heparin bolus volume. \n F32 dialysate temperature. \n @return: none """ bld = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) dia = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) dur = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) sto = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) sal = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) acd = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_6:MsgFldPositions.END_POS_FIELD_6])) bic = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_7:MsgFldPositions.END_POS_FIELD_7])) dlz = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_8:MsgFldPositions.END_POS_FIELD_8])) bpi = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_9:MsgFldPositions.END_POS_FIELD_9])) rbf = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_10:MsgFldPositions.END_POS_FIELD_10])) apl = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_11:MsgFldPositions.END_POS_FIELD_11])) aph = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_12:MsgFldPositions.END_POS_FIELD_12])) vpl = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_13:MsgFldPositions.END_POS_FIELD_13])) vph = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_14:MsgFldPositions.END_POS_FIELD_14])) hdr = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_15:MsgFldPositions.END_POS_FIELD_15])) hbv = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_16:MsgFldPositions.END_POS_FIELD_16])) tmp = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_17:MsgFldPositions.END_POS_FIELD_17])) self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BLOOD_FLOW_RATE_ML_MIN.value] = bld[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYSATE_FLOW_RATE_ML_MIN.value] = dia[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_TREATMENT_DURATION_MIN.value] = dur[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_PRESTOP_MIN.value] = sto[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML.value] = sal[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ACID_CONCENTRATE.value] = acd[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BICARB_CONCENTRATE.value] = bic[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYZER_TYPE.value] = dlz[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BLOOD_PRESSURE_MEAS_INTERVAL_MIN.value] = bpi[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_RINSEBACK_FLOW_RATE_ML_MIN.value] = rbf[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_LOW_LIMIT_MMHG.value] = apl[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_HIGH_LIMIT_MMHG.value] = aph[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_LOW_LIMIT_MMHG.value] = vpl[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_HIGH_LIMIT_MMHG.value] = vph[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR.value] = hdr[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML.value] = hbv[0] self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYSATE_TEMPERATURE_C.value] = tmp[0] @_publish([ "treatment_parameters_valid", "blood_flow_rate_reject_reason", "dialysate_flow_rate_reject_reason", "treatment_duration_reject_reason", "heparin_pre_stop_time_reject_reason", "saline_bolus_volume_reject_reason", "acid_concentrate_reject_reason", "bicarb_concentrate_reject_reason", "dialyzer_type_reject_reason", "blood_pressure_meas_interval_reject_reason", "rinseback_flow_rate_reject_reason", "arterial_pressure_low_alarm_limit_reject_reason", "arterial_pressure_high_alarm_limit_reject_reason", "venous_pressure_low_alarm_limit_reject_reason", "venous_pressure_high_alarm_limit_reject_reason", "heparin_dispense_rate_reject_reason", "heparin_bolus_volume_reject_reason", "dialysate_temperature_reject_reason" ]) def _handler_treatment_param_settings_response(self, message): """ Handler for response from HD regarding validation of treatment parameters. @param message: response message from HD regarding validity of provided treatment parameters.\n U32 0=Treatment parameters are valid, 1=Treatment parameters are invalid. \n U32 Reject reason code for blood flow rate (0=valid). \n U32 Reject reason code for dialysate flow rate (0=valid). \n U32 Reject reason code for treatment duration (0=valid). \n U32 Reject reason code for Heparin pre-stop time (0=valid). \n U32 Reject reason code for saline bolus volume (0=valid). \n U32 Reject reason code for acid concentrate (0=valid). \n U32 Reject reason code for bicarb concentrate (0=valid). \n U32 Reject reason code for dialyzer type (0=valid). \n U32 Reject reason code for BP measurement interval (0=valid). \n U32 Reject reason code for rinseback flow rate (0=valid). \n U32 Reject reason code for arterial pressure low alarm limit (0=valid). \n U32 Reject reason code for arterial pressure high alarm limit (0=valid). \n U32 Reject reason code for venous pressure low alarm limit (0=valid). \n U32 Reject reason code for venous pressure high alarm limit (0=valid). \n U32 Reject reason code for Heparin dispense rate (0=valid). \n U32 Reject reason code for Heparin bolus volume (0=valid). \n U32 Reject reason code for dialysate temperature (0=valid). \n @return: none """ val = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) bld = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) dia = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) dur = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) sto = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) sal = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_6:MsgFldPositions.END_POS_FIELD_6])) acd = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_7:MsgFldPositions.END_POS_FIELD_7])) bic = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_8:MsgFldPositions.END_POS_FIELD_8])) dlz = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_9:MsgFldPositions.END_POS_FIELD_9])) bpi = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_10:MsgFldPositions.END_POS_FIELD_10])) rbf = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_11:MsgFldPositions.END_POS_FIELD_11])) apl = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_12:MsgFldPositions.END_POS_FIELD_12])) aph = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_13:MsgFldPositions.END_POS_FIELD_13])) vpl = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_14:MsgFldPositions.END_POS_FIELD_14])) vph = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_15:MsgFldPositions.END_POS_FIELD_15])) hdr = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_16:MsgFldPositions.END_POS_FIELD_16])) hbv = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_17:MsgFldPositions.END_POS_FIELD_17])) tmp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_18:MsgFldPositions.END_POS_FIELD_18])) if val[0] == 1: self.treatment_parameters_valid = True else: self.treatment_parameters_valid = False self.blood_flow_rate_reject_reason = bld[0] self.dialysate_flow_rate_reject_reason = dia[0] self.treatment_duration_reject_reason = dur[0] self.heparin_pre_stop_time_reject_reason = sto[0] self.saline_bolus_volume_reject_reason = sal[0] self.acid_concentrate_reject_reason = acd[0] self.bicarb_concentrate_reject_reason = bic[0] self.dialyzer_type_reject_reason = dlz[0] self.blood_pressure_meas_interval_reject_reason = bpi[0] self.rinseback_flow_rate_reject_reason = rbf[0] self.arterial_pressure_low_alarm_limit_reject_reason = apl[0] self.arterial_pressure_high_alarm_limit_reject_reason = aph[0] self.venous_pressure_low_alarm_limit_reject_reason = vpl[0] self.venous_pressure_high_alarm_limit_reject_reason = vph[0] self.heparin_dispense_rate_reject_reason = hdr[0] self.heparin_bolus_volume_reject_reason = hbv[0] self.dialysate_temperature_reject_reason = tmp[0] @_publish([ "min_treatment_duration_min", "max_treatment_duration_min", "min_uf_volume_ml", "max_uf_volume_ml", "min_dialysate_flow_rate_ml_min", "max_dialysate_flow_rate_ml_min" ]) def _handler_treatment_param_ranges(self, message): """ Handler for response from HD regarding valid treatment parameter ranges. @param message: response message from HD regarding valid treatment parameter ranges.\n U32 Minimum treatment duration setting (in min.). \n U32 Maximum treatment duration setting (in min.). \n F32 Minimum ultrafiltration volume (in mL). \n F32 Maximum ultrafiltration volume (in mL). \n U32 Minimum dialysate flow rate (in mL/min). \n U32 Maximum dialysate flow rate (in mL/min). @return: none """ mintime = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) maxtime = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) minufvol = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) maxufvol = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) mindialrt = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) maxdialrt = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_6:MsgFldPositions.END_POS_FIELD_6])) self.min_treatment_duration_min = mintime[0] self.max_treatment_duration_min = maxtime[0] self.min_uf_volume_ml = minufvol[0] self.max_uf_volume_ml = maxufvol[0] self.min_dialysate_flow_rate_ml_min = mindialrt[0] self.max_dialysate_flow_rate_ml_min = maxdialrt[0] @_publish([ "saline_bolus_request_succeeded", "saline_bolus_request_reject_reason", "saline_bolus_request_bolus_volume" ]) def _handler_saline_bolus_response(self, message): """ Handler for response from HD regarding saline bolus request. @param message: response message from HD regarding saline bolus request.\n BOOL Accepted \n U32 Reject reason (if not accepted) \n U32 Saline bolus volume (mL) @return: none """ rsp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) rea = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) vol = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) if rsp[0] == 1: self.saline_bolus_request_succeeded = True else: self.saline_bolus_request_succeeded = False if RequestRejectReasons.has_value(rea[0]): self.saline_bolus_request_reject_reason = RequestRejectReasons(rea[0]) self.saline_bolus_request_bolus_volume = vol[0] @_publish([ "duration_change_succeeded", "duration_change_reject_reason", "duration_change_time_min", "duration_change_uf_vol_ml" ]) def _handler_treatment_duration_change_response(self, message): """ Handler for response from HD regarding treatment duration change request. @param message: response message from HD regarding treatment duration change.\n BOOL Accepted \n U32 Reject reason (if not accepted) \n U32 treatment duration (min) \n F32 UF volue (mL) \n @return: none """ rsp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) rea = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) tim = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) vol = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) self.duration_change_succeeded = rsp[0] if RequestRejectReasons.has_value(rea[0]): self.duration_change_reject_reason = RequestRejectReasons(rea[0]) self.duration_change_time_min = tim[0] self.duration_change_uf_vol_ml = vol[0] @_publish([ "blood_and_dialysate_flow_rate_change_succeeded", "blood_and_dialysate_flow_rate_change_reject_reason", "target_blood_flow_rate", "target_dialysate_flow_rate" ]) def _handler_blood_and_dialysate_change_response(self, message): """ Handler for response from HD regarding blood & dialysate flow rate change request. @param message: response message from HD regarding requested blood & dialysate flow rate settings change.\n BOOL Accepted \n U32 Reject reason (if not accepted) \n U32 Blood flow rate (mL/min) \n U32 Dialysate flow rate (mL/min) \n @return: none """ rsp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) rea = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) bld = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) dil = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) if rsp[0] == self.RESPONSE_REJECTED: resp = False else: resp = True self.blood_and_dialysate_flow_rate_change_succeeded = resp if RequestRejectReasons.has_value(rea[0]): self.blood_and_dialysate_flow_rate_change_reject_reason = RequestRejectReasons(rea[0]) self.target_blood_flow_rate = bld[0] self.target_dialysate_flow_rate = dil[0] @_publish([ "uf_change_succeeded", "uf_change_reject_reason", "uf_change_volume_ml", "uf_change_time_min", "uf_change_time_diff", "uf_change_rate_ml_min", "uf_change_rate_diff" ]) def _handler_uf_change_response(self, message): """ Handler for response from HD regarding UF change request. @param message: response message from HD regarding requested ultrafiltration settings change.\n BOOL Accepted \n U32 RejectReason (if not accepted) F32 UF Volume (mL) - converted to Liters \n U32 treatment Time (min) \n S32 treatment Time Change (min) \n F32 UF Rate (mL/min) \n F32 UF Rate Change (mL/min) @return: none """ rsp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) rea = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) vol = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) tim = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) tmd = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) rat = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_6:MsgFldPositions.END_POS_FIELD_6])) rtd = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_7:MsgFldPositions.END_POS_FIELD_7])) ort = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_8:MsgFldPositions.END_POS_FIELD_8])) if rsp[0] == self.RESPONSE_REJECTED: resp = False else: resp = True self.uf_change_succeeded = resp if RequestRejectReasons.has_value(rea[0]): self.uf_change_reject_reason = RequestRejectReasons(rea[0]) self.uf_change_volume_ml = vol[0] #/ self.LITER_TO_ML_CONVERSION_FACTOR self.uf_change_time_min = tim[0] self.uf_change_time_diff = tmd[0] self.uf_change_rate_ml_min = rat[0] self.uf_change_rate_diff = rtd[0] self.uf_old_rate_ml_min = ort[0] @_publish(["uf_change_succeeded", "uf_change_reject_reason", "uf_change_volume_ml", "uf_change_time_min", "uf_change_rate_ml_min"]) def _handler_uf_change_confirm_response(self, message): """ Handler for response from HD regarding UF change confirmation. @param message: response message from HD regarding confirmed ultrafiltration settings change.\n BOOL Accepted \n U32 RejectReason (if not accepted) F32 UF Volume (mL) - converted to Liters \n U32 treatment Time (min) \n F32 UF Rate (mL/min) \n @return: None """ rsp = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_1:MsgFldPositions.END_POS_FIELD_1])) rea = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_2:MsgFldPositions.END_POS_FIELD_2])) vol = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_3:MsgFldPositions.END_POS_FIELD_3])) tim = struct.unpack('i', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_4:MsgFldPositions.END_POS_FIELD_4])) rat = struct.unpack('f', bytearray( message['message'][MsgFldPositions.START_POS_FIELD_5:MsgFldPositions.END_POS_FIELD_5])) if rsp[0] == self.RESPONSE_REJECTED: resp = False else: resp = True self.uf_change_succeeded = resp if RequestRejectReasons.has_value(rea[0]): self.uf_change_reject_reason = RequestRejectReasons(rea[0]) self.uf_change_volume_ml = vol[0] / self.LITER_TO_ML_CONVERSION_FACTOR self.uf_change_time_min = tim[0] self.uf_change_rate_ml_min = rat[0] def cmd_ui_checkin_with_hd(self): """ Constructs and sends the ui check-in message @return: 0 """ message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_UI_CHECK_IN.value) self.logger.debug("Sending ui checkin w/ HD") self.can_interface.send(message, 0) return 0 def cmd_ui_request_hd_version(self): """ Constructs and sends the ui request for version message """ message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_REQUEST_FW_VERSIONS.value) self.logger.debug("Sending ui request for version to HD") self.can_interface.send(message, 0) def cmd_ui_uf_pause_resume(self, cmd=UF_CMD_PAUSE): """ Constructs and sends a ui UF command message @param cmd: 0 for pause, 1 for resume @return: none """ payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_UF_PAUSE_RESUME_REQUEST.value, payload=payload) if cmd == self.UF_CMD_PAUSE: str_cmd = "pause" else: str_cmd = "resume" self.logger.debug("Sending UF " + str_cmd + " command.") self.can_interface.send(message, 0) return 0 def cmd_ui_uf_settings_change_request(self, vol=0.0): """ Constructs and sends a ui UF change settings command message @param vol: (float) new ultrafiltration volume setting (in L) @return: none """ # reset response to this command so we can tell when response is received #self.UFChangeResponse = None # build command message volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_UF_SETTINGS_CHANGE_REQUEST.value, payload=volume) self.logger.debug("Sending UF settings change request.") self.can_interface.send(message, 0) return 0 def cmd_ui_uf_settings_change_confirm(self, vol=0.0, adj=UF_CMD_CHANGE_TIME_TO_ADJUST): """ Constructs and sends a ui UF change settings command message @param vol: (float) new ultrafiltration volume setting (in L) @param adj: (int) 0 for adjust time, 1 for adjust rate @return: none """ # reset response to this command so we can tell when response is received #self.UFChangeResponse = None # build command message volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) adjust = integer_to_bytearray(adj) payload = volume + adjust message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_CONFIRM_UF_SETTINGS_CHANGE.value, payload=payload) self.logger.debug("Sending UF settings change request.") self.can_interface.send(message, 0) return 0 def cmd_ui_treatment_duration_setting_change_request(self, time_min=0): """ Constructs and sends a ui UF change settings confirmed by user message @param time_min: (int) treatment time (in min). @return: none """ payload = integer_to_bytearray(time_min) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_TREATMENT_TIME_CHANGE_REQUEST.value, payload=payload) self.logger.debug("Sending treatment duration setting change request.") # Send message self.can_interface.send(message, 0) return 0 def cmd_ui_blood_and_dialysate_flow_settings_change_request(self, blood_flow, dial_flow): """ Constructs and sends a ui blood & dialysate flow settings change request by user message @param blood_flow: (int) blood flow rate set point (in mL/min). @param dial_flow: (int) dialysate flow rate set point (in mL/min). @return: none """ bld = integer_to_bytearray(blood_flow) dial = integer_to_bytearray(dial_flow) payload = bld + dial message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_BLOOD_DIAL_RATE_CHANGE_REQUEST.value, payload=payload) self.logger.debug("Sending blood & dialysate flow rate settings change request.") self.can_interface.send(message, 0) return 0 def cmd_ui_start_treatment_request(self, cmnd=START_TREATMENT_CMD_INITIATE_TREATMENT_WORKFLOW): """ Constructs and sends a ui start treatment command message Constraints: Command must be one of the following: START_TREATMENT_CMD_INITIATE_TREATMENT_WORKFLOW = 0 START_TREATMENT_CMD_CANCEL_TREATMENT_WORKFLOW = 1 START_TREATMENT_CMD_START_TREATMENT = 2 @param cmnd: (int) start treatment command code @return: none """ cmd = integer_to_bytearray(cmnd) payload = cmd message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_UI_START_TREATMENT.value, payload=payload) self.logger.debug("Sending start treatment command request.") self.can_interface.send(message, 0) return 0 def set_a_treatment_parameter(self, param_idx, value): """ Constructs and sends a set treatment parameter message Constraints: Must be logged into HD. @param param_idx: (int) index/enum of parameter to set (see TreatmentParameters enum) @param value: (int or float - depends on param_idx) value to set for given treatment parameter @return: none """ if self.TreatmentParameters.has_value(param_idx): self.treatment_parameters[self.TreatmentParameters(param_idx)] = value idx = integer_to_bytearray(param_idx) if param_idx == self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR.value: val = float_to_bytearray(value) elif param_idx == self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML.value: val = float_to_bytearray(value) elif param_idx == self.TreatmentParameters.TREATMENT_PARAM_DIALYSATE_TEMPERATURE_C.value: val = float_to_bytearray(value) elif param_idx == self.TreatmentParameters.TREATMENT_PARAM_UF_VOLUME_L.value: val = float_to_bytearray(value) else: val = integer_to_bytearray(value) payload = idx+val message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_HD_SET_PARAMETER_TREATMENT_PARAMETER.value, payload=payload) self.logger.debug("Setting treatment parameter " + param_idx + " to " + value + ".") self.can_interface.send(message, 0) else: self.logger.debug("Invalid param_idx given.") return 0 def set_treatment_parameters(self, bld_flow, dia_flow, duration, hep_rate, hep_bol, hep_stop, sal_bol, acid, bicarb, dialyzer, dia_temp, art_low, art_high, ven_low, ven_high, bp_intvl, rb_flow): """ Constructs and sends a ui set treatment parameters message Constraints: HD must be in treatment parameters mode @param bld_flow: (int) blood flow rate (in mL/min) @param dia_flow: (int) dialysate flow rate (in mL/min) @param duration: (int) treatment duration (in min) @param hep_rate: (float) Heparin dispense rate (in mL/hr) @param hep_bol: (float) Heparin bolus volume (in mL) @param hep_stop: (int) Heparin pre-stop time (in min) @param sal_bol: (int) Saline bolus volume (in mL) @param acid: (int) acid concentrate type @param bicarb: (int) bicarbonate concentrate type @param dialyzer: (int) dialyzer type @param dia_temp: (float) dialysate temperature (in deg C) @param art_low: (int) arterial pressure low alarm limit (in mmHg) @param art_high: (int) arterial pressure high alarm limit (in mmHg) @param ven_low: (int) venous pressure low alarm limit (in mmHg) @param ven_high: (int) venous pressure high alarm limit (in mmHg) @param bp_intvl: (int) blood pressure measurement interval (in min) @param rb_flow: (int) rinseback flow rate (in mL/min) @return: none """ self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BLOOD_FLOW_RATE_ML_MIN.value] = bld_flow self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYSATE_FLOW_RATE_ML_MIN.value] = dia_flow self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_TREATMENT_DURATION_MIN.value] = duration self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_PRESTOP_MIN.value] = hep_stop self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_SALINE_BOLUS_VOLUME_ML.value] = sal_bol self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ACID_CONCENTRATE.value] = acid self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BICARB_CONCENTRATE.value] = bicarb self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYZER_TYPE.value] = dialyzer self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_BLOOD_PRESSURE_MEAS_INTERVAL_MIN.value] = bp_intvl self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_RINSEBACK_FLOW_RATE_ML_MIN.value] = rb_flow self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_LOW_LIMIT_MMHG.value] = art_low self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_ARTERIAL_PRESSURE_HIGH_LIMIT_MMHG.value] = art_high self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_LOW_LIMIT_MMHG.value] = ven_low self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_VENOUS_PRESSURE_HIGH_LIMIT_MMHG.value] = ven_high self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_DISPENSE_RATE_ML_HR.value] = hep_rate self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME_ML.value] = hep_bol self.treatment_parameters[self.TreatmentParameters.TREATMENT_PARAM_DIALYSATE_TEMPERATURE_C.value] = dia_temp bld = integer_to_bytearray(bld_flow) dia = integer_to_bytearray(dia_flow) dur = integer_to_bytearray(duration) hps = integer_to_bytearray(hep_stop) sal = integer_to_bytearray(sal_bol) acc = integer_to_bytearray(acid) bic = integer_to_bytearray(bicarb) dzr = integer_to_bytearray(dialyzer) bpi = integer_to_bytearray(bp_intvl) rbf = integer_to_bytearray(rb_flow) apl = integer_to_bytearray(art_low) aph = integer_to_bytearray(art_high) vpl = integer_to_bytearray(ven_low) vph = integer_to_bytearray(ven_high) hdr = float_to_bytearray(hep_rate) hbv = float_to_bytearray(hep_bol) tmp = float_to_bytearray(dia_temp) payload = bld+dia+dur+hps+sal+acc+bic+dzr+bpi+rbf+apl+aph+vpl+vph+hdr+hbv+tmp message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_UI_NEW_TREATMENT_PARAMS.value, payload=payload) self.logger.debug("Sending treatment parameters to HD.") self.can_interface.send(message, 0) return 0 def cmd_ui_confirm_treatment_parameters(self): """ Constructs and sends a ui confirm treatment parameters message @return: none """ message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_UI_USER_CONFIRM_TREATMENT_PARAMS.value) self.logger.debug("Sending confirm treatment parameters messge.") self.can_interface.send(message, 0) return 0 def cmd_ui_request_saline_bolus(self, start=False): """ Constructs and sends a ui request for a saline bolus message Constraints: HD must be in treatment mode, dialysis sub-mode. Will not succeed if saline bolus already in progress. Will not succeed if max. saline volume has already been reached. @param start: (bool) True if we're requesting bolus start, False if bolus abort @return: none """ if start: sta = integer_to_bytearray(1) str = "start" else: sta = integer_to_bytearray(0) str = "abort" payload = sta message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_USER_SALINE_BOLUS_REQUEST.value, payload=payload) self.logger.debug("Sending request to " + str + " a saline bolus.") self.can_interface.send(message, 0) return 0