Index: leahi_dialin/td/modules/events.py =================================================================== diff -u -r8b54f610f3b5c0610bea0a481b892e8c70935765 -r3f4937e339925dde0b95f08e49969f8983c5cba4 --- leahi_dialin/td/modules/events.py (.../events.py) (revision 8b54f610f3b5c0610bea0a481b892e8c70935765) +++ leahi_dialin/td/modules/events.py (.../events.py) (revision 3f4937e339925dde0b95f08e49969f8983c5cba4) @@ -14,19 +14,16 @@ # ############################################################################ -import struct -from logging import Logger -from datetime import datetime -from time import time # Module imports from logging import Logger +from datetime import datetime # Project imports from leahi_dialin.common import td_enum_repository from leahi_dialin.common.generic_defs import DataTypes -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.msg_ids import MsgIds from leahi_dialin.protocols.CAN import CanMessenger, CanChannels -from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars from leahi_dialin.utils.base import publish @@ -49,14 +46,7 @@ message_id = MsgIds.MSG_ID_TD_EVENT.value, function = self._handler_events_sync) - self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, - message_id = MsgIds.MSG_ID_TD_OP_MODE_DATA.value, - function = self._handler_td_op_mode_sync) - self.events_timestamp = 0.0 #: The timestamp of the last Event message - self.op_mode = 0 #: The new Operation Mode value - self.sub_mode = 0 #: The new Operation Sub-Mode value - self.event_op_mode_timestamp = 0.0 #: The timestamp of the last Operation Mode change message # Dictionary of the mode as key and the sub mode states enum class as the valued self._op_mode_2_sub_mode = {td_enum_repository.TDOpModes.MODE_FAUL.name: td_enum_repository.TDFaultStates, @@ -75,65 +65,11 @@ self._event_dictionary[td_enum_repository.TDEventList(event).name] = [] - def get_td_nth_event(self, event_id, event_number=0): - """ - Returns the nth requested TD event - @param event_id the ID of the TD event types (i.e. TD_EVENT_STARTUP) - @param event_number the event number that is requested. The default is 0 meaning the last occurred event +# ============================================================ Properties ============================================================ - @returns the requested TD event number - """ - list_length = len(self._event_dictionary[td_enum_repository.TDEventList(event_id).name]) - if list_length == 0: - event = [] - elif event_number > list_length: - event = self._event_dictionary[td_enum_repository.TDEventList(event_id).name][list_length - 1] - else: - event = self._event_dictionary[td_enum_repository.TDEventList(event_id).name][list_length - event_number - 1] - - return event - - - def clear_td_event_list(self): - """ - Clears the TD event list - - @returns none - """ - for key in self._event_dictionary: - self._event_dictionary[key].clear() - - - def get_td_events(self, event_id, number_of_events=1): - """ - Returns the requested number of a certain TD event ID - - @param event_id the ID of the TD event types (i.e. TD_EVENT_STARTUP) - @param number_of_events the last number of messages of a certain event type - - @returns a list of the requested TD event type - """ - list_of_events = [] - - # If there are not enough event lists send all the events that are available - if len(self._event_dictionary[td_enum_repository.TDEventList(event_id).name]) <= number_of_events: - list_of_events = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] - else: - # Get the all the events - complete_list = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] - # Since the last are located at the end of the list, iterate backwards for the defined - # event messages - for i in range(len(complete_list) - 1, len(complete_list) - number_of_events - 1, -1): - list_of_events.append(complete_list[i]) - - if number_of_events == 0: - list_of_events = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] - - return list_of_events - - +# ============================================================ Handlers ============================================================ @publish(["msg_id_td_event", "events_timestamp", '_event_dictionary']) def _handler_events_sync(self, message, timestamp=0.0): """ @@ -142,57 +78,47 @@ @param message: published TD events data message @returns none """ - event_data_1 = 0 - event_data_2 = 0 - op_mode = 0 - sub_mode = 0 - sub_state = 0 + event_id = LocalVars('event_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') + op_mode = LocalVars('op_mode') + sub_mode = LocalVars('sub_mode') + state = LocalVars('state') + sub_state = LocalVars('sub_state') - event_id = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - # Convert the event ID to enum - event_enum = td_enum_repository.TDEventList(event_id) - current_timestamp = datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S.%f') - + msg_list = [] + msg_list.append((event_id, DataTypes.U32)) if event_enum is td_enum_repository.TDEventList.TD_EVENT_OPERATION_STATUS: - # Get the data type - irrelevant - event_data_type_1 = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - # Opmode data is compressed into the 4 byte - op_mode = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.START_POS_FIELD_3+1]))[0] - sub_mode = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3+1:MsgFieldPositions.START_POS_FIELD_3+2]))[0] - sub_state = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3+2:MsgFieldPositions.START_POS_FIELD_3+3]))[0] - _ = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4+3:MsgFieldPositions.END_POS_FIELD_4]))[0] - - event_data_type_2 = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - event_data_2 = struct.unpack(DataTypes(event_data_type_2).unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + msg_list.append((data_typ_1, DataTypes.U32)) # It's not used in operation status case + msg_list.append((op_mode, DataTypes.U08)) + msg_list.append((sub_mode, DataTypes.U08)) + msg_list.append((state, DataTypes.U08)) + msg_list.append((sub_state, DataTypes.U08)) + msg_list.append((data_typ_2, DataTypes.U32)) + msg_list.append((data_2, 'data_typ_2')) else: - # Get the data type - event_data_type_1 = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - # Get the data value by unpacking the data type - event_data_1 = struct.unpack(DataTypes(event_data_type_1).unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + 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')) - event_data_type_2 = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - event_data_2 = struct.unpack(DataTypes(event_data_type_2).unpack_attrib(), bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + self.process_into_vars(decoder_list = msg_list, message = message) + # Convert the event ID to enum + event_enum = td_enum_repository.TDEventList(event_id.value) + # Get the current timestamp and create a tuple of the current events - event_tuple = (current_timestamp, event_enum.name, event_data_1, event_data_2) + current_timestamp = datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S.%f') + event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) + # Check if the event state name is operation mode change. If it is, get the name of the operation modes # from the op modes enum class if event_enum is td_enum_repository.TDEventList.TD_EVENT_OP_MODE_CHANGE: - event_data_1 = td_enum_repository.TDOpModes(event_data_1).name - event_data_2 = td_enum_repository.TDOpModes(event_data_2).name - event_tuple = (current_timestamp, event_enum.name, event_data_1, event_data_2) + data_1 = td_enum_repository.TDOpModes(data_1.value).name + data_2 = td_enum_repository.TDOpModes(data_2.value).name + event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) # Check if the event state name is sub mode change. elif event_enum is td_enum_repository.TDEventList.TD_EVENT_SUB_MODE_CHANGE: # Get the Op Mode Change messages @@ -218,20 +144,20 @@ # In case the Op Mode Change is older then the previous Sub Mode Change, # use the current Op Mode from the previous Op Mode Change message for both data if prev_op_mode_timestamp <= prev_sub_mode_timestamp: - event_data_1 = self._op_mode_2_sub_mode[last_op_mode_message[3]](event_data_1).name - event_data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](event_data_2).name + data_1 = self._op_mode_2_sub_mode[last_op_mode_message[3]](data_1.value).name + data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](data_2.value).name # In case the Op Mode Change is newer then the previous Sub Mode Change, # use the operation mode informations from the last Op Mode Change message else: - event_data_1 = self._op_mode_2_sub_mode[last_op_mode_message[2]](event_data_1).name - event_data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](event_data_2).name + data_1 = self._op_mode_2_sub_mode[last_op_mode_message[2]](data_1.value).name + data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](data_2.value).name # In case this is the very first Sub Mode Change message, # use the operation mode informations from the last Op Mode Change message else: - event_data_1 = self._op_mode_2_sub_mode[last_op_mode_message[2]](event_data_1).name - event_data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](event_data_2).name + data_1 = self._op_mode_2_sub_mode[last_op_mode_message[2]](data_1.value).name + data_2 = self._op_mode_2_sub_mode[last_op_mode_message[3]](data_2.value).name # In case there are no Op Mode Change messages, use the Operations States messages # to identify the Op Modes for the Sub Modes @@ -252,52 +178,95 @@ for i in range(len(op_status_list) - 1, -1, -1): op_status_msg = op_status_list[i] - # Look for a match for event_data_2 + # Look for a match for data_2.value if not data_2_found: - if op_status_msg[2] == event_data_2: + if op_status_msg[2] == data_2.value: event_2_op_mode = td_enum_repository.TDOpModes(op_status_msg[1]).name data_2_found = True - # Look for a match for event_data_1 after event_data_2 is found - # Criteria is that the opmode, submode pair can't be the same as the one found for event_data_2 + # Look for a match for data_1.value after data_2.value is found + # Criteria is that the opmode, submode pair can't be the same as the one found for data_2.value else: - if op_status_msg[2] == event_data_1 and \ - (op_status_msg[2] != event_data_2 or td_enum_repository.TDOpModes(op_status_msg[1]).name != event_2_op_mode): + if op_status_msg[2] == data_1.value and \ + (op_status_msg[2] != data_2.value or td_enum_repository.TDOpModes(op_status_msg[1]).name != event_2_op_mode): event_1_op_mode = td_enum_repository.TDOpModes(op_status_msg[1]).name - # If op mode for event_data_2 found but not found for event_data_1 and run out of operation states + # If op mode for data_2.value found but not found for data_1.value and run out of operation states # assume it's the start of the unit start up and the going to standby is not logged yet if event_2_op_mode != self.UNKNOWN_STATE and event_1_op_mode == self.UNKNOWN_STATE: event_1_op_mode = td_enum_repository.TDOpModes.MODE_STAN.name # Update the event_data values - event_data_1 = self._op_mode_2_sub_mode[event_1_op_mode](event_data_1).name - event_data_2 = self._op_mode_2_sub_mode[event_2_op_mode](event_data_2).name + data_1 = self._op_mode_2_sub_mode[event_1_op_mode](data_1.value).name + data_2 = self._op_mode_2_sub_mode[event_2_op_mode](data_2.value).name # Update the tuple - event_tuple = (current_timestamp, event_enum.name, event_data_1, event_data_2) + event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) elif event_enum is td_enum_repository.TDEventList.TD_EVENT_OPERATION_STATUS: - event_tuple = (current_timestamp, op_mode, sub_mode, sub_state) + event_tuple = (current_timestamp, op_mode.value, sub_mode.value, state.value) # Update event dictionary self._event_dictionary[event_enum.name].append(event_tuple) self.events_timestamp = timestamp - @publish(["msg_id_td_op_mode_data", "event_op_mode_timestamp", "op_mode", "sub_mode"]) - def _handler_td_op_mode_sync(self, message, timestamp=0.0): + +# ============================================================ Support ============================================================ + def get_td_nth_event(self, event_id, event_number=0): """ - Handles published TD operation mode messages. Current TD operation mode - is captured for reference. + Returns the nth requested TD event - @param message: published TD operation mode broadcast message - @return: None + @param event_id the ID of the TD event types (i.e. TD_EVENT_STARTUP) + @param event_number the event number that is requested. The default is 0 meaning the last occurred event + + @returns the requested TD event number """ - msg_list = [] - msg_list.append(('self.op_mode', DataTypes.U32)) - msg_list.append(('self.sub_mode', DataTypes.U32)) + list_length = len(self._event_dictionary[td_enum_repository.TDEventList(event_id).name]) - self.process_into_vars(decoder_list = msg_list, - message = message) - self.event_op_mode_timestamp = timestamp + if list_length == 0: + event = [] + elif event_number > list_length: + event = self._event_dictionary[td_enum_repository.TDEventList(event_id).name][list_length - 1] + else: + event = self._event_dictionary[td_enum_repository.TDEventList(event_id).name][list_length - event_number - 1] + + return event + + + def clear_td_event_list(self): + """ + Clears the TD event list + + @returns none + """ + for key in self._event_dictionary: + self._event_dictionary[key].clear() + + + def get_td_events(self, event_id, number_of_events=1): + """ + Returns the requested number of a certain TD event ID + + @param event_id the ID of the TD event types (i.e. TD_EVENT_STARTUP) + @param number_of_events the last number of messages of a certain event type + + @returns a list of the requested TD event type + """ + list_of_events = [] + + # If there are not enough event lists send all the events that are available + if len(self._event_dictionary[td_enum_repository.TDEventList(event_id).name]) <= number_of_events: + list_of_events = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] + else: + # Get the all the events + complete_list = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] + # Since the last are located at the end of the list, iterate backwards for the defined + # event messages + for i in range(len(complete_list) - 1, len(complete_list) - number_of_events - 1, -1): + list_of_events.append(complete_list[i]) + + if number_of_events == 0: + list_of_events = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] + + return list_of_events