Index: leahi_dialin/common/generic_defs.py =================================================================== diff -u -r6c90336ac2cd8cf34ac620cff431a847d9ddf557 -rb167367cb2256f8b4a35bc2c9cde6cde2129d05d --- leahi_dialin/common/generic_defs.py (.../generic_defs.py) (revision 6c90336ac2cd8cf34ac620cff431a847d9ddf557) +++ leahi_dialin/common/generic_defs.py (.../generic_defs.py) (revision b167367cb2256f8b4a35bc2c9cde6cde2129d05d) @@ -59,3 +59,103 @@ 'BOOL_U08': [], 'NUM_OF_DATA_TYPES': [], } + + +@unique +class AlarmLampPatterns(DialinEnum): + OFF = 0 + OK = 1 + FAULT = 2 + HIGH = 3 + MEDIUM = 4 + LOW = 5 + MANUAL = 6 + NUM_OF_ALARM_LAMP_PATTERNS = 7 + +AlarmLampPatterns._str_list = { + 'OFF':[], + 'OK':[], + 'FAULT':[], + 'HIGH':[], + 'MEDIUM':[], + 'LOW':[], + 'MANUAL':[], + 'NUM_OF_ALARM_LAMP_PATTERNS':[] +} + + +@unique +class AlarmPriorities(DialinEnum): + NONE = 0 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + NUM_OF_ALARM_PRIORITIES = 4 + +AlarmPriorities._str_list = { + 'NONE': [], + 'LOW': [], + 'MEDIUM': [], + 'HIGH': [], + 'NUM_OF_ALARM_PRIORITIES': [] +} + + +@unique +class AlarmProperties(DialinEnum): + PRIORITY = 0 # + RANK = 1 # + SOURCE = 2 # + SYSTEM_FAULT = 3 # + DD_FAULT = 4 # + STOPS = 5 # + CLEAR_IMMEDIATELY = 6 # + NO_CLEAR = 7 # + NO_RESUME = 8 # + NO_RINSEBACK = 9 # + NO_END_TREATMENT = 10 # + NOT_IN_RINSEBACK = 11 # + NOT_IN_POST_TREATMENT = 12 # + NO_BLOOD_RECIRC = 13 # + NO_DIAL_RECIRC = 14 # + AUTO_RESUME = 15 # + CLEAR_ALARM_ONLY = 16 # + TREATMENT_LOG = 17 # + NUM_OF_ALARM_PROPERTIES = 18 # + +AlarmProperties._str_list = { + 'PRIORITY': [], + 'RANK': [], + 'SOURCE': [], + 'SYSTEM_FAULT': [], + 'DD_FAULT': [], + 'STOPS': [], + 'CLEAR_IMMEDIATELY': [], + 'NO_CLEAR': [], + 'NO_RESUME': [], + 'NO_RINSEBACK': [], + 'NO_END_TREATMENT': [], + 'NOT_IN_RINSEBACK': [], + 'NOT_IN_POST_TREATMENT': [], + 'NO_BLOOD_RECIRC': [], + 'NO_DIAL_RECIRC': [], + 'AUTO_RESUME': [], + 'CLEAR_ALARM_ONLY': [], + 'TREATMENT_LOG': [], + 'NUM_OF_ALARM_PROPERTIES ': [] +} + + +@unique +class AlarmResponseButtons(DialinEnum): + RESUME = 0 + RINSEBACK = 1 + END_TREATMENT = 2 + NUM_OF_TD_ALARM_RESPONSE_BUTTONS = 3 + +AlarmResponseButtons._str_list = { + 'RESUME': [], + 'RINSEBACK': [], + 'END_TREATMENT': [], + 'NUM_OF_TD_ALARM_RESPONSE_BUTTONS': [] +} Index: leahi_dialin/common/td_defs_proxy.py =================================================================== diff -u -r636775bd0ba262967bcf06e194658b97720e2517 -rb167367cb2256f8b4a35bc2c9cde6cde2129d05d --- leahi_dialin/common/td_defs_proxy.py (.../td_defs_proxy.py) (revision 636775bd0ba262967bcf06e194658b97720e2517) +++ leahi_dialin/common/td_defs_proxy.py (.../td_defs_proxy.py) (revision b167367cb2256f8b4a35bc2c9cde6cde2129d05d) @@ -95,4 +95,10 @@ TDTreatmentModalityTypes = td_defs.TDTreatmentModalityTypes TDTreatmentHDFDilution = td_defs.TDTreatmentHDFDilution + # Alarms + AlarmLampPatterns = generic_defs.AlarmLampPatterns + AlarmPriorities = generic_defs.AlarmPriorities + AlarmProperties = generic_defs.AlarmProperties + AlarmResponseButtons = generic_defs.AlarmResponseButtons + td_enum_repository = TD_Defs() Index: leahi_dialin/td/modules/alarms.py =================================================================== diff -u -rc2f174da6eec4d8ce0e76a1926beb5ca1d9680ea -rb167367cb2256f8b4a35bc2c9cde6cde2129d05d --- leahi_dialin/td/modules/alarms.py (.../alarms.py) (revision c2f174da6eec4d8ce0e76a1926beb5ca1d9680ea) +++ leahi_dialin/td/modules/alarms.py (.../alarms.py) (revision b167367cb2256f8b4a35bc2c9cde6cde2129d05d) @@ -17,63 +17,24 @@ # Module imports from functools import partial from logging import Logger -import struct -from enum import unique # Project imports -from leahi_dialin.common.alarm_defs import AlarmList +from leahi_dialin.common import td_enum_repository, AlarmList from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common.generic_defs import DataTypes -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import CanMessenger, CanMessage, CanChannels -from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.protocols.CAN import CanMessenger, CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray, float_to_bytearray -from leahi_dialin.utils.enums import DialinEnum class TDAlarms(AbstractSubSystem): """ TD interface containing alarm related commands. """ - # Alarm lamp patterns - TD_ALARM_LAMP_PATTERN_OFF = 0 - TD_ALARM_LAMP_PATTERN_OK = 1 - TD_ALARM_LAMP_PATTERN_FAULT = 2 - TD_ALARM_LAMP_PATTERN_HIGH = 3 - TD_ALARM_LAMP_PATTERN_MEDIUM = 4 - TD_ALARM_LAMP_PATTERN_LOW = 5 - TD_ALARM_LAMP_PATTERN_MANUAL = 6 - - # Alarm priority states - TD_ALARM_STATE_NONE = 0 - TD_ALARM_STATE_LOW = 1 - TD_ALARM_STATE_MEDIUM = 2 - TD_ALARM_STATE_HIGH = 3 - - # Alarm response buttons - @unique - class AlarmResponseButtons(DialinEnum): - TD_ALARM_RESPONSE_BUTTON_RESUME = 0 - TD_ALARM_RESPONSE_BUTTON_RINSEBACK = 1 - TD_ALARM_RESPONSE_BUTTON_END_TREATMENT = 2 - NUM_OF_TD_ALARM_RESPONSE_BUTTONS = 3 - AlarmResponseButtons._str_list = {} - - # Alarm status message field positions - START_POS_ALARM_STATE = CanMessage.PAYLOAD_START_INDEX - END_POS_ALARM_STATE = START_POS_ALARM_STATE + 4 - START_POS_ALARM_TOP = END_POS_ALARM_STATE - END_POS_ALARM_TOP = START_POS_ALARM_TOP + 4 - START_POS_ALARM_ESCALATES_IN = END_POS_ALARM_TOP - END_POS_ALARM_ESCALATES_IN = START_POS_ALARM_ESCALATES_IN + 4 - START_POS_ALARM_SILENCE_EXPIRES_IN = END_POS_ALARM_ESCALATES_IN - END_POS_ALARM_SILENCE_EXPIRES_IN = START_POS_ALARM_SILENCE_EXPIRES_IN + 4 - START_POS_ALARMS_FLAGS = END_POS_ALARM_SILENCE_EXPIRES_IN - END_POS_ALARMS_FLAGS = START_POS_ALARMS_FLAGS + 2 - def __init__(self, can_interface: CanMessenger, logger: Logger): """ @param can_interface: Can Messenger object @@ -119,11 +80,11 @@ self.alarm_table_timestamp = 0.0 #: The timestamp of the last Alarm Table Properties message # composite alarm status based on latest TD alarm status broadcast message - self.alarms_priority_state = 0 #: The current Top Alarm's priority value - self.alarm_top = 0 #: The current Top Alarm's value - self.alarms_silence_expires_in = 0 #: How many seconds the silence for the alarms expires in - self.alarms_escalates_in = 0 #: How many seconds the current Alarm escalates to the next priority - self.alarms_flags = 0 #: The Alarm flag's value + self.alarms_priority_state = 0 + self.alarm_top = 0 + self.alarms_silence_expires_in = 0 + self.alarms_escalates_in = 0 + self.alarms_flags = 0 self.alarm_states = [False] * 500 #: The States of all Alarms data in list format self.alarm_conditions = [False] * 500 #: The Conditions of all Alarms data in list format @@ -137,25 +98,24 @@ self.last_alarm_data_2 = 0.0 #: The last Alarm's data part 2 # alarm information - self.alarm_volume = 0 #: The Alarm's Volume level - self.alarm_audio_curr_hg = 0.0 #: The Alarm's Audio high current - self.alarm_audio_curr_lg = 0.0 #: The Alarm's Audio low current - self.alarm_backup_audio_curr = 0.0 #: The Alarm's Audio backup current - self.safety_shutdown_active = False #: The Safety Shutdown is active or not - self.ac_power_lost = False #: The AC Power is lost or not - self.alarm_table_button_blockers = [False] * self.AlarmResponseButtons.NUM_OF_TD_ALARM_RESPONSE_BUTTONS.value #: The Alarm Table's Button blocker data - self.alarm_state_button_blockers = [False] * self.AlarmResponseButtons.NUM_OF_TD_ALARM_RESPONSE_BUTTONS.value #: The Alarm State's Button blocker data + self.alarm_volume = 0 + self.alarm_audio_curr_hg = 0.0 + self.alarm_audio_curr_lg = 0.0 + self.alarm_backup_audio_curr = 0.0 + self.safety_shutdown_active = False + self.ac_power_lost = False + self.alarm_table_button_blockers = [False] * td_enum_repository.AlarmResponseButtons.NUM_OF_TD_ALARM_RESPONSE_BUTTONS.value # Alarms list - self.ui_alarm_list_accepted = True #: The Alarm List request accepted - self.ui_alarm_list_reject_reason = 0 #: The Alarm List request reject reason - self.ui_alarm_list = [] #: The UI Alarm List content + self.ui_alarm_list_accepted = True + self.ui_alarm_list_reject_reason = 0 + self.ui_alarm_list = [] self.ui_alarm_list_timestamp = 0.0 #: The timestamp of the last Alarm List # Alarm Table Properties - self.alarm_table = {} #: The Alarm Table with Alarm Property details - + self.alarm_table = {} + def clear_dialin_alarms(self): """ Clears the alarms states in Dialin. @@ -166,6 +126,203 @@ self.alarm_states[x] = False +# ============================================================ Properties ============================================================ + @property + def alarms_priority_state(self): + """ + The current Top Alarm's priority value + """ + return self._alarms_priority_state + + @alarms_priority_state.setter + def alarms_priority_state(self, value): + self._alarms_priority_state = value + + + @property + def alarm_top(self): + """ + The current Top Alarm's value + """ + return self._alarm_top + + @alarm_top.setter + def alarm_top(self, value): + self._alarm_top = value + + + @property + def alarms_silence_expires_in(self): + """ + How many seconds the silence for the alarms expires in + """ + return self._alarms_silence_expires_in + + @alarms_silence_expires_in.setter + def alarms_silence_expires_in(self, value): + self._alarms_silence_expires_in = value + + + @property + def alarms_escalates_in(self): + """ + How many seconds the current Alarm escalates to the next priority + """ + return self._alarms_escalates_in + + @alarms_escalates_in.setter + def alarms_escalates_in(self, value): + self._alarms_escalates_in = value + + + @property + def alarms_flags(self): + """ + The Alarm flag's value + """ + return self._alarms_flags + + @alarms_flags.setter + def alarms_flags(self, value): + self._alarms_flags = value + + + @property + def alarm_volume(self): + """ + The Alarm's Volume level + """ + return self._alarm_volume + + @alarm_volume.setter + def alarm_volume(self, value): + self._alarm_volume = value + + + @property + def alarm_audio_curr_hg(self): + """ + The Alarm's Audio high current + """ + return self._alarm_audio_curr_hg + + @alarm_audio_curr_hg.setter + def alarm_audio_curr_hg(self, value): + self._alarm_audio_curr_hg = value + + + @property + def alarm_audio_curr_lg(self): + """ + The Alarm's Audio low current + """ + return self._alarm_audio_curr_lg + + @alarm_audio_curr_lg.setter + def alarm_audio_curr_lg(self, value): + self._alarm_audio_curr_lg = value + + + @property + def alarm_backup_audio_curr(self): + """ + The Alarm's Audio backup current + """ + return self._alarm_backup_audio_curr + + @alarm_backup_audio_curr.setter + def alarm_backup_audio_curr(self, value): + self._alarm_backup_audio_curr = value + + + @property + def safety_shutdown_active(self): + """ + The Safety Shutdown is active or not + """ + return self._safety_shutdown_active + + @safety_shutdown_active.setter + def safety_shutdown_active(self, value): + self._safety_shutdown_active = value + + + @property + def ac_power_lost(self): + """ + The AC Power is lost or not + """ + return self._ac_power_lost + + @ac_power_lost.setter + def ac_power_lost(self, value): + self._ac_power_lost = value + + + @property + def alarm_table_button_blockers(self): + """ + The Alarm Table's Button blocker data + """ + return self._alarm_table_button_blockers + + @alarm_table_button_blockers.setter + def alarm_table_button_blockers(self, value): + self._alarm_table_button_blockers = value + + + @property + def ui_alarm_list_accepted(self): + """ + The UI Alarm List request accepted + """ + return self._ui_alarm_list_accepted + + @ui_alarm_list_accepted.setter + def ui_alarm_list_accepted(self, value): + self._ui_alarm_list_accepted = value + + + @property + def ui_alarm_list_reject_reason(self): + """ + The UI Alarm List request reject reason + """ + return self._ui_alarm_list_reject_reason + + @ui_alarm_list_reject_reason.setter + def ui_alarm_list_reject_reason(self, value): + self._ui_alarm_list_reject_reason = value + + + @property + def ui_alarm_list(self): + """ + The UI Alarm List content + """ + return self._ui_alarm_list + + @ui_alarm_list.setter + def ui_alarm_list(self, value): + self._ui_alarm_list = value + + + @property + def alarm_table(self): + """ + The Alarm Table with Alarm Property details + """ + return self._alarm_table + + @alarm_table.setter + def alarm_table(self, value): + self._alarm_table = value + + + + + +# ============================================================ Handlers ============================================================ @publish(["msg_id_td_alarm_status_data", "alarms_priority_state", "alarm_top", "alarms_silence_expires_in", "alarms_escalates_in", "alarms_flags", "td_alarm_status_timestamp"]) @@ -178,14 +335,13 @@ @return: none """ msg_list = [] - msg_list.append(('self.alarms_priority_state', DataTypes.U32)) - msg_list.append(('self.alarm_top', DataTypes.U32)) - msg_list.append(('self.alarms_escalates_in', DataTypes.U32)) - msg_list.append(('self.alarms_silence_expires_in', DataTypes.U32)) - msg_list.append(('self.alarms_flags', DataTypes.U16)) + msg_list.append((type(self).alarms_priority_state, DataTypes.U32)) + msg_list.append((type(self).alarm_top, DataTypes.U32)) + msg_list.append((type(self).alarms_escalates_in, DataTypes.U32)) + msg_list.append((type(self).alarms_silence_expires_in, DataTypes.U32)) + msg_list.append((type(self).alarms_flags, DataTypes.U16)) - self.process_into_vars(decoder_list = msg_list, - message = message) + self.process_into_vars_2(decoder_list = msg_list, message = message) self.td_alarm_status_timestamp = timestamp @@ -199,42 +355,38 @@ @param message: published TD alarm activation message @return: none """ - self.logger.debug("Alarm activated!") + alarm_id = LocalVars('alarm_id') + data_typ_1 = LocalVars('data_typ_1') + data_1 = LocalVars('data_1') + data_typ_2 = LocalVars('data_typ_2') + data_2 = LocalVars('data_2') + priority = LocalVars('priority') + rank = LocalVars('rank') + clr_top_only = LocalVars('clr_top_only') result = {} msg_list = [] - msg_list.append(('alarm_id', DataTypes.U32)) - msg_list.append(('data_typ_1', DataTypes.U32)) - msg_list.append(('data_1', 'data_typ_1')) - msg_list.append(('data_typ_2', DataTypes.U32)) - msg_list.append(('data_2', 'data_typ_2')) - msg_list.append(('priority', DataTypes.U32)) - msg_list.append(('rank', DataTypes.U32)) - msg_list.append(('clr_top_only', DataTypes.U32)) + msg_list.append((alarm_id, DataTypes.U32)) + msg_list.append((data_typ_1, DataTypes.U32)) + msg_list.append((data_1, 'data_typ_1')) + msg_list.append((data_typ_2, DataTypes.U32)) + msg_list.append((data_2, 'data_typ_2')) + msg_list.append((priority, DataTypes.U32)) + msg_list.append((rank, DataTypes.U32)) + msg_list.append((clr_top_only, DataTypes.U32)) - i = 1 - for msg_detail in msg_list: - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - if isinstance(msg_detail[1], DataTypes): - unpack_attrib = msg_detail[1].unpack_attrib() - else: - unpack_attrib = DataTypes(result[msg_detail[1]]).unpack_attrib() - - value = struct.unpack(unpack_attrib, bytearray(message['message'][start_pos:end_pos]))[0] - result[msg_detail[0]] = value - i += 1 + self.process_into_vars_2(decoder_list = msg_list, message = message) - self.logger.debug("Alarm ID: %d %d %d" % (result['alarm_id'], result['data_1'], result['data_2'])) - self.alarm_states[result['alarm_id']] = True - self.alarm_conditions[result['alarm_id']] = True - self.alarm_priorities[result['alarm_id']] = result['priority'] - self.alarm_ranks[result['alarm_id']] = result['rank'] - self.alarm_clear_top_only_flags[result['alarm_id']] = result['clr_top_only'] - self.alarm_data[result['alarm_id']] = [result['data_1'], result['data_2']] - self.last_alarm_triggered = result['alarm_id'] - self.last_alarm_data_1 = result['data_1'] - self.last_alarm_data_2 = result['data_2'] + self.logger.debug("Alarm ID: %d %d %d" % (alarm_id.value, data_1.value, data_2.value)) + self.alarm_states[alarm_id.value] = True + self.alarm_conditions[alarm_id.value] = True + self.alarm_priorities[alarm_id.value] = priority.value + self.alarm_ranks[alarm_id.value] = rank.value + self.alarm_clear_top_only_flags[alarm_id.value] = clr_top_only.value + self.alarm_data[alarm_id.value] = [data_1.value, data_2.value] + self.last_alarm_triggered = alarm_id.value + self.last_alarm_data_1 = data_1.value + self.last_alarm_data_2 = data_2.value self.td_alarm_triggered_timestamp = timestamp @@ -246,13 +398,15 @@ @param message: published TD alarm clear message @return: none """ + alarm_id = LocalVars('alarm_id') + msg_list = [] - msg_list.append(('alarm_id', DataTypes.U32)) + msg_list.append((alarm_id, DataTypes.U32)) - result = self.process_into_vars(decoder_list = msg_list, - message = message) - self.alarm_states[result['alarm_id']] = False - self.alarm_conditions[result['alarm_id']] = False + self.process_into_vars_2(decoder_list = msg_list, message = message) + + self.alarm_states[alarm_id.value] = False + self.alarm_conditions[alarm_id.value] = False self.td_alarm_cleared_timestamp = timestamp @@ -264,19 +418,20 @@ @param message: published TD alarm clear alarm condition message @return: none """ + alarm_id = LocalVars('alarm_id') + msg_list = [] - msg_list.append(('alarm_id', DataTypes.U32)) + msg_list.append((alarm_id, DataTypes.U32)) - result = self.process_into_vars(decoder_list = msg_list, - message = message) + self.process_into_vars_2(decoder_list = msg_list, message = message) - self.alarm_conditions[result['alarm_id']] = False + self.alarm_conditions[alarm_id.value] = False self.td_alarm_clr_condition_timestamp = timestamp @publish(["msg_id_td_alarm_info_data", "alarm_volume", "alarm_audio_curr_hg", "alarm_audio_curr_lg", "alarm_backup_audio_curr", "safety_shutdown_active", "ac_power_lost", - "alarm_table_button_blockers", "alarm_state_button_blockers", + "alarm_table_button_blockers", "td_alarm_information_timestamp"]) def _handler_alarm_information_sync(self, message, timestamp=0.0): """ @@ -286,26 +441,20 @@ @return: none """ msg_list = [] - msg_list.append(('self.alarm_volume', DataTypes.U32)) - msg_list.append(('self.alarm_audio_curr_hg', DataTypes.F32)) - msg_list.append(('self.alarm_audio_curr_lg', DataTypes.F32)) - msg_list.append(('self.alarm_backup_audio_curr', DataTypes.U32)) - msg_list.append(('self.safety_shutdown_active', DataTypes.BOOL)) - msg_list.append(('self.ac_power_lost', DataTypes.BOOL)) - sensor_list = [] - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_RESUME.value, DataTypes.BOOL_U08)) - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_RINSEBACK.value, DataTypes.BOOL_U08)) - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_END_TREATMENT.value, DataTypes.BOOL_U08)) - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_RESUME.value, DataTypes.BOOL_U08)) - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_RINSEBACK.value, DataTypes.BOOL_U08)) - sensor_list.append((self.AlarmResponseButtons.TD_ALARM_RESPONSE_BUTTON_END_TREATMENT.value, DataTypes.BOOL_U08)) + msg_list.append((type(self).alarm_volume, DataTypes.U32)) + msg_list.append((type(self).alarm_audio_curr_hg, DataTypes.F32)) + msg_list.append((type(self).alarm_audio_curr_lg, DataTypes.F32)) + msg_list.append((type(self).alarm_backup_audio_curr, DataTypes.U32)) + msg_list.append((type(self).safety_shutdown_active, DataTypes.BOOL)) + msg_list.append((type(self).ac_power_lost, DataTypes.BOOL)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.RESUME.value, DataTypes.BOOL_U08)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.RINSEBACK.value, DataTypes.BOOL_U08)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.END_TREATMENT.value, DataTypes.BOOL_U08)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.RESUME.value, DataTypes.BOOL_U08)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.RINSEBACK.value, DataTypes.BOOL_U08)) + msg_list.append((self.alarm_table_button_blockers, td_enum_repository.AlarmResponseButtons.END_TREATMENT.value, DataTypes.BOOL_U08)) - self.process_into_vars(decoder_list = msg_list, - message = message) - self.process_into_dict(dict_to_update = self.alarm_table_button_blockers, - decoder_list = sensor_list, - message = message, - start_from_byte = len(msg_list) * DataTypes.U32.size()) + self.process_into_vars_2(decoder_list = msg_list, message = message) self.td_alarm_information_timestamp = timestamp @@ -318,16 +467,22 @@ @param message: published TD alarm list response message @return: none """ - self.ui_alarm_list_accepted = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.ui_alarm_list_reject_reason = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + msg_list = [] + msg_list.append((type(self).ui_alarm_list_accepted, DataTypes.U32)) + msg_list.append((type(self).ui_alarm_list_reject_reason, DataTypes.U32)) + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #1 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #2 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #3 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #4 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #5 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #6 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #7 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #8 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #9 + msg_list.append((self.ui_alarm_list, DataTypes.U32)) # UI Alarm #10 - i = 3 - for _ in range(0,10): - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - value = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray(message['message'][start_pos:end_pos]))[0] - self.ui_alarm_list.append(value) - i += 1 + self.process_into_vars_2(decoder_list = msg_list, message = message) + self.ui_alarm_list_timestamp = timestamp @@ -339,40 +494,60 @@ @param message: published TD alarm table properties message @return: none """ + priority = LocalVars('priority') + rank = LocalVars('rank') + source = LocalVars('source') + system_fault = LocalVars('system_fault') + dd_fault = LocalVars('dd_fault') + stops = LocalVars('stops') + clear_immediately = LocalVars('clear_immediately') + no_clear = LocalVars('no_clear') + no_resume = LocalVars('no_resume') + no_rinseback = LocalVars('no_rinseback') + no_end_treatment = LocalVars('no_end_treatment') + not_in_rinseback = LocalVars('not_in_rinseback') + not_in_post_treatment = LocalVars('not_in_post_treatment') + no_blood_recirc = LocalVars('no_blood_recirc') + no_dial_recirc = LocalVars('no_dial_recirc') + auto_resume = LocalVars('auto_resume') + clear_alarm_only = LocalVars('clear_alarm_only') + treatment_log = LocalVars('treatment_log') + alarm_id = LocalVars('alarm_id') + properties_list = [] - properties_list.append(('Priority', DataTypes.U16)) - properties_list.append(('Rank', DataTypes.U16)) - properties_list.append(('Source', DataTypes.U08)) - properties_list.append(('System_Fault', DataTypes.BOOL_U08)) - properties_list.append(('DD_Fault', DataTypes.BOOL_U08)) - properties_list.append(('Stops', DataTypes.BOOL_U08)) - properties_list.append(('Clear_Immediately', DataTypes.BOOL_U08)) - properties_list.append(('No_Clear', DataTypes.BOOL_U08)) - properties_list.append(('No_Resume', DataTypes.BOOL_U08)) - properties_list.append(('No_Rinseback', DataTypes.BOOL_U08)) - properties_list.append(('No_End_Treatment', DataTypes.BOOL_U08)) - properties_list.append(('Not_in_Rinseback', DataTypes.BOOL_U08)) - properties_list.append(('Not_in_Post_Treatment', DataTypes.BOOL_U08)) - properties_list.append(('No_Blood_Recirc', DataTypes.BOOL_U08)) - properties_list.append(('No_Dial_Recirc', DataTypes.BOOL_U08)) - properties_list.append(('Auto_Resume', DataTypes.BOOL_U08)) - properties_list.append(('Clear_Alarm_Only', DataTypes.BOOL_U08)) - properties_list.append(('Treatment_Log', DataTypes.BOOL_U08)) - properties_list.append(('Alarm_Id', DataTypes.U16)) + properties_list.append((priority, DataTypes.U16)) + properties_list.append((rank, DataTypes.U16)) + properties_list.append((source, DataTypes.U08)) + properties_list.append((system_fault, DataTypes.BOOL_U08)) + properties_list.append((dd_fault, DataTypes.BOOL_U08)) + properties_list.append((stops, DataTypes.BOOL_U08)) + properties_list.append((clear_immediately, DataTypes.BOOL_U08)) + properties_list.append((no_clear, DataTypes.BOOL_U08)) + properties_list.append((no_resume, DataTypes.BOOL_U08)) + properties_list.append((no_rinseback, DataTypes.BOOL_U08)) + properties_list.append((no_end_treatment, DataTypes.BOOL_U08)) + properties_list.append((not_in_rinseback, DataTypes.BOOL_U08)) + properties_list.append((not_in_post_treatment, DataTypes.BOOL_U08)) + properties_list.append((no_blood_recirc, DataTypes.BOOL_U08)) + properties_list.append((no_dial_recirc, DataTypes.BOOL_U08)) + properties_list.append((auto_resume, DataTypes.BOOL_U08)) + properties_list.append((clear_alarm_only, DataTypes.BOOL_U08)) + properties_list.append((treatment_log, DataTypes.BOOL_U08)) + properties_list.append((alarm_id, DataTypes.U16)) - result = self.process_into_vars(decoder_list = properties_list, - message = message) + self.process_into_vars_2(decoder_list = properties_list, message = message) # Save the result in the table - for prop in result: - if result['Alarm_Id'] not in self.alarm_table: - self.alarm_table[result['Alarm_Id']] = {} - if prop != 'Alarm_Id': - self.alarm_table[result['Alarm_Id']][prop] = result[prop] + for prop, _ in properties_list: + if alarm_id.value not in self.alarm_table: + self.alarm_table[alarm_id.value] = {} + if prop != alarm_id.name: + self.alarm_table[alarm_id.value][prop.name] = prop.value self.alarm_table_timestamp = timestamp +# ============================================================ Overrides and Requests ============================================================ def cmd_alarm_status_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): """ Constructs and sends the alarm status broadcast interval override command Index: leahi_dialin/utils/abstract_classes.py =================================================================== diff -u -r8f1ef718ce3c23a6cc5a22ae13bc1a0627008f24 -rb167367cb2256f8b4a35bc2c9cde6cde2129d05d --- leahi_dialin/utils/abstract_classes.py (.../abstract_classes.py) (revision 8f1ef718ce3c23a6cc5a22ae13bc1a0627008f24) +++ leahi_dialin/utils/abstract_classes.py (.../abstract_classes.py) (revision b167367cb2256f8b4a35bc2c9cde6cde2129d05d) @@ -24,6 +24,16 @@ from leahi_dialin.common.constants import MSG_HEADER_SIZE +class LocalVars: + """ + Reference class for local variables + """ + + def __init__(self, name): + self.name = name + self.value = None + + class AbstractObserver(ABC): """ Publicly accessible parent class for all observers. @@ -117,6 +127,124 @@ return results + def process_into_vars_2(self, decoder_list: List[Tuple], message, start_from_byte: int=0, debug: bool=False) -> None: + """ + Process the CAN message with the help of the decoder list into variables and a dictionary. + Note: updating variables will only be done when it's class wide one, aka "self.attr_name". + For local attributes to avoid namespace issues use the returned dictionary. Format: {attr_name : value} + + :param decoder_list: (List[Tuple[String, DataTypes]]) Contains the variable name and DataType pair of the indexed message + :param message: (Bytearray) The raw CAN message + :param start_from_byte: (Integer) Start from the nth byte after the header + :param debug: (Boolean) Prints for debugging + :return: (Dictionary) A dictionary for the variable_name and value pair + """ + start_pos = MSG_HEADER_SIZE + start_from_byte + result = {} + if debug: + print(f'\n\nDecoder_list: {decoder_list}') + for decode_details in decoder_list: + # If last position is multichar length + if isinstance(decode_details[-1], int): + length = decode_details[-1] + datatype: DataTypes = decode_details[-2] + base_list_length = 3 + # If it's the normal Datatype + elif isinstance(decode_details[-1], DataTypes): + length = 1 + datatype: DataTypes = decode_details[-1] + base_list_length = 2 + # If it's a string containing the name of the datatype + else: + length = 1 + datatype = DataTypes(result[decode_details[-1]]) + base_list_length = 2 + # If it's a dictionary and the decoder list contains keys + key_list_length = len(decode_details) - base_list_length + key_1 = decode_details[1] if len(decode_details) >= base_list_length + 1 else None + key_2 = decode_details[2] if len(decode_details) >= base_list_length + 2 else None + key_3 = decode_details[3] if len(decode_details) >= base_list_length + 3 else None + end_pos = start_pos + datatype.size() + if debug: + print(f'Len: {len(decode_details)}') + print(f'key_list_length: {key_list_length}') + if key_list_length > 0: + print(f'key_1: {key_1}') + print(f'key_2: {key_2}') + print(f'key_3: {key_3}') + print(f'datatype: {datatype} - {length}') + + # Extract the value and convert it to correct type + for i in range(0, length): + end_pos = start_pos + datatype.size() + try: + new_value = struct.unpack(datatype.unpack_attrib(), bytearray(message['message'][start_pos:end_pos]))[0] + print('new_value') + if length == 1: + value = new_value + elif datatype == DataTypes.U08 and length > 1: + if i == 0: + value = chr(new_value) + else: + value += chr(new_value) + if debug: + print(f'Message Part: {message["message"][start_pos:end_pos]}') + print(f'Input Data: {bytearray(message["message"][start_pos:end_pos])}') + print(f'New value: {new_value} + -> Value: {value}') + except Exception as e: + if debug: + print('Message extraction exception occured!') + value = None + break + start_pos = end_pos + + if 'nan' in str(value).lower(): + value = None + # raise ValueError(f'{value} is not an accepted value!') + # If the type is Bool, convert the value from Integer to Boolean + if datatype in [DataTypes.BOOL, DataTypes.BOOL_U08]: + value = True if value == 1 else False + + # Save processed value into the input + if isinstance(decode_details[0], property): + property_name = decode_details[0].fget.__name__ + if debug: + print(f'Property name: {property_name} <- {value}') + decode_details[0].__set__(self, value) + result[property_name] = value + elif isinstance(decode_details[0], dict): + dict_to_update = decode_details[0] + if key_list_length == 1: + dict_to_update[key_1] = value + if debug: + print(f'Dictionary key [{key_1}] <- {value}') + elif key_list_length == 2: + if key_1 not in dict_to_update: + dict_to_update[key_1] = {} + dict_to_update[key_1][key_2] = value + if debug: + print(f'Dictionary key [{key_1}][{key_2}] <- {value}') + elif key_list_length == 3: + if key_1 not in dict_to_update: + dict_to_update[key_1] = {} + if key_2 not in dict_to_update[key_1]: + dict_to_update[key_1][key_2] = {} + dict_to_update[key_1][key_2][key_3] = value + if debug: + print(f'Dictionary key [{key_1}][{key_2}][{key_3}] <- {value}') + elif isinstance(decode_details[0], list): + decode_details[0].append(value) + else: + variable_name = decode_details[0].name + if debug: + print(f'Local variable name: {variable_name} <- {value}') + decode_details[0].value = value + result[variable_name] = value + start_pos = end_pos + if debug: + print('Finished cycle\n') + + def process_into_dict(self, dict_to_update: dict, decoder_list: List[Tuple], message, start_from_byte: int=0, debug: bool=False): """ Process the CAN message with the help of the decoder list into a dictionary.