Index: dialin/common/msg_ids.py =================================================================== diff -u -r053580d8dbe39bf313d61b002d8d41a189d95c39 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 053580d8dbe39bf313d61b002d8d41a189d95c39) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -327,6 +327,9 @@ MSG_ID_HD_GET_USAGE_INFO_RECORD = 0x807E MSG_ID_HD_SET_USAGE_INFO_RECORD = 0x807F MSG_ID_HD_SEND_USAGE_INFO_RECORD = 0x8080 + MSG_ID_HD_SET_BLOOD_LEAK_2_EMB_MODE = 0x8081 + MSG_ID_HD_SET_BLOOD_LEAK_EMB_MODE_COMMAND = 0x8082 + MSG_ID_HD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE = 0x8083 MSG_ID_DG_TESTER_LOGIN_REQUEST = 0xA000 MSG_ID_DG_ALARM_STATE_OVERRIDE = 0xA001 Index: dialin/dg/sw_configs.py =================================================================== diff -u -r053580d8dbe39bf313d61b002d8d41a189d95c39 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- dialin/dg/sw_configs.py (.../sw_configs.py) (revision 053580d8dbe39bf313d61b002d8d41a189d95c39) +++ dialin/dg/sw_configs.py (.../sw_configs.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -306,7 +306,7 @@ self._utilities.prepare_excel_report(self._FIRMWARE_STACK_NAME, self._utilities.NON_VOLATILE_RECORD_NAME, report_address) - # Create ab object of the observer class to observe the dictionary + # Create an object of the observer class to observe the dictionary observer = NVUtilsObserver("dg_sw_config_record") # Attach the observer to the list self.attach(observer) Index: dialin/hd/blood_leak.py =================================================================== diff -u -r3a70bfb451b74106348c064c34f19934aadd9119 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- dialin/hd/blood_leak.py (.../blood_leak.py) (revision 3a70bfb451b74106348c064c34f19934aadd9119) +++ dialin/hd/blood_leak.py (.../blood_leak.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -15,14 +15,53 @@ ############################################################################ import struct from logging import Logger +from enum import unique +from time import sleep from .constants import RESET, NO_RESET from ..common.msg_defs import MsgIds, MsgFieldPositions from ..protocols.CAN import DenaliMessage, DenaliChannels -from ..utils.base import AbstractSubSystem, publish -from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from ..utils.base import AbstractSubSystem, publish, DialinEnum, AbstractObserver +from ..utils.conversions import integer_to_bytearray, float_to_bytearray, bytearray_to_byte, bytearray_to_integer, \ + unsigned_short_to_bytearray, byte_to_bytearray +@unique +class EmbModeCommands(DialinEnum): + NU = 0 # NULL command + CS = 1 # Control S command (this is handled automatically) + SP = 2 # Set point command + T = 3 + G = 4 + I = 5 + V = 6 + Z = 7 + Q = 8 + D = 9 + C = 10 + + +class BloodLeakObserver(AbstractObserver): + """ + + Observation class + """ + + def __init__(self, prop): + self.received = False + self.prop = prop + + def update(self, message): + """ + Publicly accessible function to provide an update of the object that is being observed + + @param message: (str) the message to update its status + + @return none + """ + self.received = message.get(self.prop, False) + + class HDBloodLeak(AbstractSubSystem): """ HDBloodLeak @@ -55,6 +94,11 @@ self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_blood_leak_sync) + channel_id = DenaliChannels.hd_to_dialin_ch_id + msg_id = MsgIds.MSG_ID_HD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_blood_leak_emb_mode_cmd_resp) + self.blood_leak_status = self.NO_BLOOD_LEAK_DETECTED self.blood_leak_state = self.BLOOD_LEAK_INIT_STATE self.blood_leak_zeroed_status_counter = 0 @@ -65,6 +109,8 @@ self.blood_leak_st_count = 0 self.blood_leak_led_intensity = 0 self.blood_leak_register_counter = 0 + self.blood_leak_emb_mode_cmd_response = '' + self._is_emb_mode_command_in_progress = False def get_blood_leak_status(self): """ @@ -146,6 +192,28 @@ """ return self.blood_leak_register_counter + def get_blood_leak_emb_mode_command_response(self): + """ + Gets the embedded mode command response + + @return: string - embedded mode command response + """ + # Check if there has been a recent command sent to the firmware and then start an observer + # If there is no command sent and therefore, there is no pending response, the observer will hang + if self._is_emb_mode_command_in_progress is True: + # Create an object of the observer class to observe the response + observer = BloodLeakObserver("blood_leak_emb_mode_cmd_response") + # Attach the observer to the list + self.attach(observer) + + # Wait until data has been received from firmware + while not observer.received: + sleep(0.1) + # Done with receiving the response from the firmware + self._is_emb_mode_command_in_progress = False + + return self.blood_leak_emb_mode_cmd_response + @publish(['blood_leak_status', 'blood_leak_state', 'blood_leak_zeroed_status_counter', 'blood_leak_counter', 'blood_leak_zeroed_status', 'blood_leak_detect_set_point', 'blood_leak_detect_level', 'blood_leak_st_count', 'blood_leak_led_intensity', 'blood_leak_register_counter']) @@ -273,3 +341,75 @@ else: self.logger.debug("Timeout!!!!") return False + + def cmd_blood_leak_set_to_embedded_mode(self): + """ + Constructs and sends switching to embedded mode command + + @return: non-zero integer if successful, False otherwise + """ + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SET_BLOOD_LEAK_2_EMB_MODE.value) + + self.logger.debug("Setting the blood leak to embedded mode") + + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + self._is_emb_mode_command_in_progress = True + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + + def cmd_blood_leak_set_embedded_mode_command(self, command: int, msg_payload: int = None): + """ + Constructs and sends switching to embedded mode command + + @return: non-zero integer if successful, False otherwise + """ + command_bytes = byte_to_bytearray(command) + data = 0 + + if msg_payload is not None: + data = msg_payload + + data = unsigned_short_to_bytearray(data) + payload = command_bytes + data + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_SET_BLOOD_LEAK_EMB_MODE_COMMAND.value, + payload=payload) + + self.logger.debug("Sending " + str(EmbModeCommands(command).name) + " to the blood leak sensor") + + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + self._is_emb_mode_command_in_progress = True + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + + @publish(['blood_leak_emb_mode_cmd_response']) + def _handler_blood_leak_emb_mode_cmd_resp(self, message): + """ + Handles published blood leak status messages. Blood leak status is captured + for reference. + + @param message: published blood leak status message + @return: None + """ + payload = message['message'] + index = MsgFieldPositions.START_POS_FIELD_1 + length, index = bytearray_to_integer(payload, index, False) + + for i in range(0, length): + # Loop through the length and get the + char, char_index = bytearray_to_byte(payload, index + i, False) + self.blood_leak_emb_mode_cmd_response += chr(char) + Index: dialin/utils/conversions.py =================================================================== diff -u -re0221f00fe32642b76d4a03c61e3f5ce2da2c881 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- dialin/utils/conversions.py (.../conversions.py) (revision e0221f00fe32642b76d4a03c61e3f5ce2da2c881) +++ dialin/utils/conversions.py (.../conversions.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -26,7 +26,7 @@ """ if type(val) != int: raise ValueError("Expected integer but received {0} with type {1}".format(val, type(val))) - return struct.pack(" bytes: Index: tests/dg_nvm_scripts.py =================================================================== diff -u -r053580d8dbe39bf313d61b002d8d41a189d95c39 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- tests/dg_nvm_scripts.py (.../dg_nvm_scripts.py) (revision 053580d8dbe39bf313d61b002d8d41a189d95c39) +++ tests/dg_nvm_scripts.py (.../dg_nvm_scripts.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -27,7 +27,7 @@ # It creates a folder called DG_NV_Records in the destination that is called # If no address is provided, the default location is one folder above the dialin folder wherever it is installed # in your computer. - #dg.sw_configs.cmd_get_dg_sw_config_record() + dg.sw_configs.cmd_get_dg_sw_config_record() # Use cmd_set_dg_sw_config_record() set the changes back to firmware # This function requires an address for the excel report. Use the absolute address of your excel report like the @@ -49,15 +49,15 @@ # It creates a folder called DG_NV_Records in the destination that is called # If no address is provided, the default location is one folder above the dialin folder wherever it is installed # in you computer. - # dg.calibration_record.cmd_get_dg_calibration_record_report() + #dg.calibration_record.cmd_get_dg_calibration_record_report() # Use cmd_set_dg_calibration_excel_to_fw() set the changes back to firmware # This function requires an address for the excel report. Use the absolute address of your excel report like the # example below - # dg.calibration_record.cmd_set_dg_calibration_excel_to_fw('/home/fw/projects/DG_NV_Records/2022-03-31-DG-Record.xlsx') + dg.calibration_record.cmd_set_dg_calibration_excel_to_fw('/home/fw/projects/DG_NV_Records/2022-05-03-DG-Record.xlsx') # For resetting the calibration record to benign values, use the function below - dg.calibration_record.cmd_reset_dg_calibration_record() + #dg.calibration_record.cmd_reset_dg_calibration_record() if __name__ == "__main__": @@ -66,9 +66,9 @@ if dg.cmd_log_in_to_dg(): - run_sw_configs_commands() + #run_sw_configs_commands() - #run_calibration_commands() + run_calibration_commands() #dg.usage_record.cmd_get_dg_usage_info_record() #dg.usage_record.cmd_update_dg_usage_info_record('/home/fw/projects/DG_NV_Records/2022-04-22-DG-Record.xlsx') Index: tests/dg_tests.py =================================================================== diff -u -r053580d8dbe39bf313d61b002d8d41a189d95c39 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- tests/dg_tests.py (.../dg_tests.py) (revision 053580d8dbe39bf313d61b002d8d41a189d95c39) +++ tests/dg_tests.py (.../dg_tests.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -39,6 +39,7 @@ from dialin.dg.fans import DGFansNames from dialin.dg.pressures import DGPressures from dialin.dg.conductivity_sensors import ConductivitySensorsEnum +from dialin.dg.voltages import DGMonitoredVoltages from time import sleep from datetime import datetime import sys @@ -78,7 +79,7 @@ .format(HDOpModes(hd.hd_operation_mode).name, hd.hd_operation_sub_mode, hd.alarms.alarm_top, hd.dialysate_outlet_flow.reference_dialysate_outlet_uf_volume, hd.dialysate_outlet_flow.measured_dialysate_outlet_uf_volume, - PreTreatmentWetSelfTesStates(hd.pretreatment.pre_treatment_wet_self_test_state).name, + 0, #PreTreatmentWetSelfTesStates(hd.pretreatment.pre_treatment_wet_self_test_state).name, PostTreatmentStates(hd.post_treatment.post_treatment_sub_mode).name, HDPostTreatmentDrainStates(hd.post_treatment.post_treatment_drain_state).name)) return info @@ -185,12 +186,14 @@ def get_heaters_info(): info = ('Pri_main_DC, {:5.3f}, Pri_state, {}, Trimmer_DC, {:5.3f}, Trimmer_state, {}, ' 'Primary_target_temp, {:5.3f}, Trimmer_target_temp, {:5.3f}, Primary_eff, {:5.3f}, Dia_flow, {:5.3f}, ' - 'Interim_int_temp, {:5.3f}, Heater_RO_flow, {:5.3f}, '. + 'Interim_int_temp, {:5.3f}, Heater_RO_flow, {:5.3f}, Primary_volt, {:5.3f}, Trimmer_volt, {:5.3f}, '. format(dg.heaters.main_primary_heater_duty_cycle, dg.heaters.primary_heater_state, dg.heaters.trimmer_heater_duty_cycle, dg.heaters.trimmer_heater_state, dg.heaters.primary_heaters_target_temperature, dg.heaters.trimmer_heater_target_temperature, dg.heaters.primary_efficiency, dg.heaters.temporary_remove_flow, - dg.heaters.temporary_internal_target, dg.heaters.temporary_target_ro_flow)) + dg.heaters.temporary_internal_target, dg.heaters.temporary_target_ro_flow, + dg.voltages.monitored_voltages[DGMonitoredVoltages.MONITORED_LINE_24V_PRIM_HTR_V.value], + dg.voltages.monitored_voltages[DGMonitoredVoltages.MONITORED_LINE_24V_TRIM_HTR_V.value])) return info @@ -420,7 +423,7 @@ def collect_hd_treatment(): f = open("/home/fw/projects/dialin/tests/treatment_run_hd.log", "w") - hd.cmd_hd_software_reset_request() + #hd.cmd_hd_software_reset_request() try: while True: @@ -619,22 +622,24 @@ hd.cmd_log_in_to_hd() sleep(1) - # run_heat_disinfect() + #run_heat_disinfect() # run_chemical_disinfect() # run_dg() # cmd_set_disinfect_ui_screen() - collect_treatment_data() + #collect_treatment_data() - # collect_hd_treatment() + #collect_hd_treatment() # test_hd_fans_alarms() # test_dg_fans_alarms() - #while True: - # print(get_hd_fans_info(), get_hd_occlusion_pressures_info()) - # sleep(1) + while True: + print(get_hd_fans_info()) + sleep(1) + #dg.ro_pump.cmd_ro_pump_measured_flow_rate_override(0.0, reset=1) + Index: tests/hd_blood_leak_data.py =================================================================== diff -u -r88b4967ce6b9ac816ac21b26326450de4b540887 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- tests/hd_blood_leak_data.py (.../hd_blood_leak_data.py) (revision 88b4967ce6b9ac816ac21b26326450de4b540887) +++ tests/hd_blood_leak_data.py (.../hd_blood_leak_data.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -18,6 +18,7 @@ sys.path.append("..") from dialin.hd.hemodialysis_device import HD from dialin.common.hd_defs import HDOpModes +from dialin.hd.blood_leak import EmbModeCommands from time import sleep from datetime import datetime @@ -36,14 +37,23 @@ if __name__ == "__main__": # Create an HD object called hd - hd = HD() + hd = HD(log_level='DEBUG') + hd.cmd_log_in_to_hd() sleep(2) - hd.cmd_log_in_to_hd() + #hd.blood_leak.cmd_blood_leak_data_broadcast_interval_override(50) + + #hd.blood_leak.cmd_blood_leak_set_to_embedded_mode() + + hd.blood_leak.cmd_blood_leak_set_embedded_mode_command(EmbModeCommands.Q.value, msg_payload=100) + + print(hd.blood_leak.get_blood_leak_emb_mode_command_response()) + sleep(1) - hd.blood_leak.cmd_blood_leak_data_broadcast_interval_override(50) + print(hd.blood_leak.get_blood_leak_emb_mode_command_response()) + """ f = open("/home/fw/projects/dialin/tests/blood_leak.log", "w") try: @@ -52,9 +62,10 @@ var = str(datetime.now()) + ', ' + hd_blood_leak + '\r' - print(var) - f.write(var) - sleep(0.05) + #print(var) + #f.write(var) + sleep(1) except KeyboardInterrupt: f.close() + """ Index: tests/hd_nvm_scripts.py =================================================================== diff -u -r053580d8dbe39bf313d61b002d8d41a189d95c39 -rf5ed119ffe4c4cf520b22221073b1ff9a6f5968a --- tests/hd_nvm_scripts.py (.../hd_nvm_scripts.py) (revision 053580d8dbe39bf313d61b002d8d41a189d95c39) +++ tests/hd_nvm_scripts.py (.../hd_nvm_scripts.py) (revision f5ed119ffe4c4cf520b22221073b1ff9a6f5968a) @@ -71,3 +71,4 @@ # Comment this function if not needed #run_calibration_commands() +