Index: dialin/common/msg_defs.py =================================================================== diff -u -r300390c34a81a42b5eb606e4f4499a1439bfc432 -r4e0bf0b10bac641750ac24b32cbc1f2f438fb1be --- dialin/common/msg_defs.py (.../msg_defs.py) (revision 300390c34a81a42b5eb606e4f4499a1439bfc432) +++ dialin/common/msg_defs.py (.../msg_defs.py) (revision 4e0bf0b10bac641750ac24b32cbc1f2f438fb1be) @@ -99,13 +99,17 @@ MSG_ID_UI_SET_ALARM_AUDIO_VOLUME_LEVEL_CMD = 0x4E # UI command to set alarm audio volume level MSG_ID_UI_PRE_TREATMENT_UF_REQUEST = 0x4F # UI UF Initialization Request MSG_ID_HD_PRE_TREATMENT_UF_RESPONSE = 0x50 # HD response to user request to adjust the ultrafiltration in pre-treatment + MSG_ID_DG_COMMAND_RESPONSE = 0x51 # DG response to command from HD + MSG_ID_UI_RINSEBACK_CMD = 0x52 # UI rinseback request MSG_ID_HD_RINSEBACK_CMD_RESPONSE = 0x53 # HD rinseback request response + MSG_ID_UI_RECIRC_CMD = 0x54 # UI re-circ request MSG_ID_HD_RECIRC_CMD_RESPONSE = 0x55 # HD re-circ request response MSG_ID_HD_RINSEBACK_PROGRESS = 0x56 # HD broadcast of rinseback progress - MSG_ID_HD_RECIRCULATE_PROGRESS = 0x5A # HD broadcast of recirculate progress - MSG_ID_HD_BLOOD_PRIME_PROGRESS = 0x59 # HD broadcast of blood prime progress MSG_ID_UI_TX_END_CMD = 0x57 # UI end treatment sub-mode user request MSG_ID_HD_TX_END_CMD_RESPONSE = 0x58 # HD end treatment sub-mode user request response + MSG_ID_HD_BLOOD_PRIME_PROGRESS = 0x59 # HD broadcast of blood prime progress + MSG_ID_HD_RECIRC_PROGRESS = 0x5A # HD broadcast of treatment re-circulate progress + MSG_ID_DG_CHANGE_VALVE_SETTING_CMD = 0x5B # HD request to DG to change valve setting MSG_ID_PRE_TREATMENT_STATE = 0x5C # HD broadcast of pre-treatment state MSG_ID_UI_SAMPLE_WATER_CMD = 0x5D # UI sample water sub-mode user request MSG_ID_HD_SAMPLE_WATER_CMD_RESPONSE = 0x5E # HD sample water sub-mode request response @@ -136,7 +140,7 @@ MSG_ID_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE = 0x800A # Blood pump motor controller speed override request MSG_ID_BLOOD_PUMP_MC_MEAS_CURR_OVERRIDE = 0x800B # Blood pump motor controller current override request MSG_ID_BLOOD_FLOW_SEND_INTERVAL_OVERRIDE = 0x800C # Blood flow broadcast interval override request - MSG_ID___AVAILABLE_1 = 0x800D # This msg ID is available for use + MSG_ID_TREATMENT_TIME_REMAINING_OVERRIDE = 0x800D # This msg ID is available for use MSG_ID_BLOOD_PUMP_MEAS_SPEED_OVERRIDE = 0x800E # Blood pump measured motor speed override request MSG_ID_BLOOD_PUMP_MEAS_ROTOR_SPEED_OVERRIDE = 0x800F # Blood pump measured rotor speed override request MSG_ID_DIAL_IN_FLOW_SET_PT_OVERRIDE = 0x8010 # Dialysate inlet flow set point override request @@ -184,6 +188,16 @@ MSG_ID_SUPER_CLEAR_ALARMS_CMD = 0x803A # Clears all alarms (even if non-recoverable or fault) MSG_ID_HD_REQUEST_CALIBRATION_DATA = 0x803B # Requests calibration data from HD MSG_ID_HD_ERASE_CALIBRATION_DATA = 0x803C # Requests calibration data on HD be erased + MSG_ID_HD_SET_CALIBRATION_RECORD = 0x803D # HD set calibration record that is received from Dialin + MSG_ID_HD_GET_CALIBRATION_RECORD = 0x803E # HD get calibration record that is requested from Dialin + MSG_ID_HD_SEND_CALIBRATION_RECORD = 0x803F # HD send calibration record to CAN bus to be received in Dialin (equivalent to publish) + MSG_ID_HD_SET_SYSTEM_RECORD = 0x8040 # HD set system record that is received from Dialin + MSG_ID_HD_GET_SYSTEM_RECORD = 0x8041 # HD get system record that is requested from Dialin + MSG_ID_HD_SEND_SYSTEM_RECORD = 0x8042 # HD send system record to CAN bus to be received in Dialin (equivalent to publish) + MSG_ID_HD_GET_SERVICE_RECORD = 0x8043 # HD get service record that is requested from Dialin + MSG_ID_HD_SET_SERVICE_RECORD = 0x8044 # HD set service record that is received from Dialin + MSG_ID_HD_SEND_SERVICE_RECORD = 0x8045 # HD send service record to CAN bus to be received in Dialin (equivalent to publish) + MSG_ID_HD_SET_OP_MODE_REQUEST = 0x8046 # HD set operation mode request MSG_ID_DG_TESTER_LOGIN_REQUEST = 0XA000 # DG tester log-in MSG_ID_DG_ALARM_STATE_OVERRIDE = 0xA001 # DG alarm state override message ID Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -rc83af5f3c56db1049d5fde362848a0200279d585 -r4e0bf0b10bac641750ac24b32cbc1f2f438fb1be --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision c83af5f3c56db1049d5fde362848a0200279d585) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 4e0bf0b10bac641750ac24b32cbc1f2f438fb1be) @@ -52,8 +52,7 @@ HD_OP_MODE_SERVICE = 1 HD_OP_MODE_INIT_POST = 2 HD_OP_MODE_STANDBY = 3 - HD_OP_MODE_PRESCRIPTION = 4 - HD_OP_MODE_OP_PARAMS = 5 + HD_OP_MODE_TREATMENT_PARAMS = 4 HD_OP_MODE_PRE_TREATMENT = 6 HD_OP_MODE_TREATMENT = 7 HD_OP_MODE_POST_TREATMENT = 8 @@ -280,6 +279,48 @@ self.logger.debug("Timeout!!!!") return False + def cmd_hd_set_operation_mode(self, newMode=0): + """ + Constructs and sends a set operation mode request command via CAN bus. + Constraints: + Must be logged into HD. + Transition from current to requested op mode must be legal. + + @param newMode: ID of operation mode to transition to + HD_OP_MODE_FAULT = 0 + HD_OP_MODE_SERVICE = 1 + HD_OP_MODE_INIT_POST = 2 + HD_OP_MODE_STANDBY = 3 + HD_OP_MODE_TREATMENT_PARAMS = 4 + HD_OP_MODE_PRE_TREATMENT = 6 + HD_OP_MODE_TREATMENT = 7 + HD_OP_MODE_POST_TREATMENT = 8 + + @return: 1 if successful, zero otherwise + + """ + + payload = integer_to_bytearray(newMode) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SET_OP_MODE_REQUEST.value, + payload=payload) + + self.logger.debug("Requesting HD mode change to " + str(newMode)) + + # Send message + received_message = self.can_interface.send(message) + + if received_message is not None: + if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: + self.logger.debug("Success: Mode change accepted") + else: + self.logger.debug("Failure: Mode change rejected.") + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("HD mode change request Timeout!!!!") + return False + def cmd_hd_safety_shutdown_override(self, active=True, reset=NO_RESET): """ Constructs and sends an HD safety shutdown override command via CAN bus. Index: dialin/hd/ui_proxy.py =================================================================== diff -u -r300390c34a81a42b5eb606e4f4499a1439bfc432 -r4e0bf0b10bac641750ac24b32cbc1f2f438fb1be --- dialin/hd/ui_proxy.py (.../ui_proxy.py) (revision 300390c34a81a42b5eb606e4f4499a1439bfc432) +++ dialin/hd/ui_proxy.py (.../ui_proxy.py) (revision 4e0bf0b10bac641750ac24b32cbc1f2f438fb1be) @@ -108,6 +108,45 @@ def has_value(cls, value): return value in cls._value2member_map_ + class RinsebackUserActions(enum.Enum): + + REQUESTED_USER_ACTION_RINSEBACK_CONFIRM_START = 0, + REQUESTED_USER_ACTION_RINSEBACK_INCREASE_RATE = 1, + REQUESTED_USER_ACTION_RINSEBACK_DECREASE_RATE = 2, + REQUESTED_USER_ACTION_RINSEBACK_PAUSE = 3, + REQUESTED_USER_ACTION_RINSEBACK_RESUME = 4, + REQUESTED_USER_ACTION_RINSEBACK_END = 5, + REQUESTED_USER_ACTION_RINSEBACK_ADDITIONAL = 6, + REQUESTED_USER_ACTION_RINSEBACK_CONFIRM_DISCONNECT = 7, + REQUESTED_USER_ACTION_RINSEBACK_END_TREATMENT = 8, + REQUESTED_USER_ACTION_RINSEBACK_BACK_TO_TREATMENT = 9, + NUM_OF_REQUESTED_RINSEBACK_USER_ACTIONS = 10 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + class RecircUserActions(enum.Enum): + + REQUESTED_USER_ACTION_TX_RECIRC_RECONNECT = 0, + REQUESTED_USER_ACTION_TX_RECIRC_CONFIRM_RECONNECT = 1, + REQUESTED_USER_ACTION_TX_RECIRC_RESUME_RC = 2, + REQUESTED_USER_ACTION_TX_RECIRC_END_TREATMENT = 3, + NUM_OF_REQUESTED_TX_RECIRC_USER_ACTIONS = 4 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + class TreatmentEndUserActions(enum.Enum): + + REQUESTED_USER_ACTION_TX_END_RINSEBACK_START = 0, + NUM_OF_REQUESTED_TX_END_USER_ACTIONS = 1 + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + def __init__(self, can_interface, logger: Logger): """ @@ -145,6 +184,12 @@ self._handler_saline_bolus_response) self.can_interface.register_receiving_publication_function(DenaliChannels.ui_to_hd_ch_id, MsgIds.MSG_ID_UI_PRE_TREATMENT_UF_REQUEST.value, self._handler_uf_volume_setting_response) + self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_RINSEBACK_CMD_RESPONSE.value, + self._handler_rinseback_cmd_response) + self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_RECIRC_CMD_RESPONSE.value, + self._handler_recirc_cmd_response) + self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, MsgIds.MSG_ID_HD_TX_END_CMD_RESPONSE.value, + self._handler_treatment_end_cmd_response) # initialize variables that will be populated by HD version response self.hd_version = None @@ -185,6 +230,15 @@ self.saline_bolus_request_succeeded = False self.saline_bolus_request_reject_reason = 0 self.saline_bolus_request_bolus_volume = 0 + # initialize variables that will be populated by response to rinseback command + self.rinseback_cmd_succeeded = False + self.rinseback_cmd_reject_reason = 0 + # initialize variables that will be populated by response to recirculate command + self.recirc_cmd_succeeded = False + self.recirc_cmd_reject_reason = 0 + # initialize variables that will be populated by response to treatment end command + self.treatment_end_cmd_succeeded = False + self.treatment_end_cmd_reject_reason = 0 self.reject_reasons = OrderedDict() for attr in dir(self): @@ -1104,6 +1158,84 @@ self.uf_change_time_min = tim[0] self.uf_change_rate_ml_min = rat[0] + @_publish([ + "rinseback_cmd_succeeded", + "rinseback_cmd_reject_reason", + ]) + def _handler_rinseback_cmd_response(self, message): + """ + Handler for response from HD regarding rinseback user command. + + @param message: response message from HD regarding rinseback user command.\n + BOOL Accepted \n + U32 Reject reason (if not accepted) \n + + @return: None + """ + rsp = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + rea = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + + if rsp[0] == 1: + self.rinseback_cmd_succeeded = True + else: + self.rinseback_cmd_succeeded = False + if RequestRejectReasons.has_value(rea[0]): + self.rinseback_cmd_reject_reason = RequestRejectReasons(rea[0]) + + @_publish([ + "recirc_cmd_succeeded", + "recirc_cmd_reject_reason", + ]) + def _handler_recirc_cmd_response(self, message): + """ + Handler for response from HD regarding recirculate user command. + + @param message: response message from HD regarding recirculate user command.\n + BOOL Accepted \n + U32 Reject reason (if not accepted) \n + + @return: None + """ + rsp = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + rea = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + + if rsp[0] == 1: + self.recirc_cmd_succeeded = True + else: + self.recirc_cmd_succeeded = False + if RequestRejectReasons.has_value(rea[0]): + self.recirc_cmd_reject_reason = RequestRejectReasons(rea[0]) + + @_publish([ + "treatment_end_cmd_succeeded", + "treatment_end_cmd_reject_reason", + ]) + def _handler_treatment_end_cmd_response(self, message): + """ + Handler for response from HD regarding treatment end user command. + + @param message: response message from HD regarding treatment end user command.\n + BOOL Accepted \n + U32 Reject reason (if not accepted) \n + + @return: None + """ + rsp = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + rea = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + + if rsp[0] == 1: + self.treatment_end_cmd_succeeded = True + else: + self.treatment_end_cmd_succeeded = False + if RequestRejectReasons.has_value(rea[0]): + self.treatment_end_cmd_reject_reason = RequestRejectReasons(rea[0]) + def cmd_ui_checkin_with_hd(self): """ Constructs and sends the ui check-in message @@ -1463,6 +1595,87 @@ self.can_interface.send(message, 0) + def cmd_ui_rinseback_user_action(self, action=RinsebackUserActions.REQUESTED_USER_ACTION_RINSEBACK_CONFIRM_START.value): + """ + Constructs and sends a UI rinseback user action message + Constraints: + HD must be in treatment mode, rinseback sub-mode. + + @param action: (enumerated int) User action + CONFIRM_START = 0 (start rinseback) + INCREASE_RATE = 1 (increase rinseback flow rate by 25 mL/min) + DECREASE_RATE = 2 (decrease rinseback flow rate by 25 mL/min) + PAUSE = 3 (pause rinseback) + RESUME = 4 (resume paused rinseback) + RINSEBACK_END = 5 (end rinseback now) + ADDITIONAL = 6 (10 mL more) + CONFIRM_DISCONNECT = 7 (go to re-circulate sub-mode) + END_TREATMENT = 8 (go to post-treatment mode) + BACK_TO_TREATMENT = 9 (ready to resume treatment) + + @return: none + """ + + cmd = integer_to_bytearray(action) + + payload = cmd + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_UI_RINSEBACK_CMD.value, + payload=payload) + + self.logger.debug("Sending rinseback command " + str(action) + " to HD.") + + self.can_interface.send(message, 0) + + def cmd_ui_recirculate_user_action(self, action=RecircUserActions.REQUESTED_USER_ACTION_TX_RECIRC_RECONNECT.value): + """ + Constructs and sends a UI recirculate user action message + Constraints: + HD must be in treatment mode, recirculate sub-mode. + + @param action: (enumerated int) User action + RECONNECT = 0 (ready to reconnect patient) + CONFIRM_RECONNECT = 1 (confirm patient is reconnected - ready to resume treatment) + RESUME_RC = 2 (resume recirculation - not ready to reconnect patient) + END_TREATMENT = 3 (go to post-treatment mode) + + @return: none + """ + + cmd = integer_to_bytearray(action) + + payload = cmd + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_UI_RECIRC_CMD.value, + payload=payload) + + self.logger.debug("Sending recirculate command " + str(action) + " to HD.") + + self.can_interface.send(message, 0) + + def cmd_ui_treatment_end_user_action(self, action=TreatmentEndUserActions.REQUESTED_USER_ACTION_TX_END_RINSEBACK_START.value): + """ + Constructs and sends a UI treatment end user action message + Constraints: + HD must be in treatment mode, treatment end sub-mode. + + @param action: (enumerated int) User action + RINSEBACK_START = 0 (start final rinseback) + + @return: none + """ + + cmd = integer_to_bytearray(action) + + payload = cmd + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_UI_TX_END_CMD.value, + payload=payload) + + self.logger.debug("Sending treatment end command " + str(action) + " to HD.") + + self.can_interface.send(message, 0) + def cmd_ui_user_alarm_response(self, option=AlarmUserOptions.ALARM_USER_ACTION_ACK.value): """ Constructs and sends a ui alarm response message.