Index: dialin/protocols/CAN.py =================================================================== diff -u -re193e10da7d6c16158592c1aae7ebe1221dd0cde -r37a2357f479e70d4e7744f7deba72fffadb79aa5 --- dialin/protocols/CAN.py (.../CAN.py) (revision e193e10da7d6c16158592c1aae7ebe1221dd0cde) +++ dialin/protocols/CAN.py (.../CAN.py) (revision 37a2357f479e70d4e7744f7deba72fffadb79aa5) @@ -17,6 +17,7 @@ import threading from collections import deque import asyncio +from typing import Callable import can from can.interfaces import socketcan @@ -27,6 +28,7 @@ from logging import Logger import struct from .. import common +from ..common import MsgIds from ..utils import SingletonMeta from concurrent.futures import ThreadPoolExecutor @@ -306,16 +308,25 @@ def get_message_id(message): """ Returns request ID from packet - @param message: complete Diality Packet - @return:: integer with request ID """ msg_id_array = message['message'][DenaliMessage.MSG_ID_INDEX: DenaliMessage.PAYLOAD_LENGTH_INDEX] + return int.from_bytes(msg_id_array, DenaliMessage.BYTE_ORDER) - return int.from_bytes(msg_id_array, byteorder=DenaliMessage.BYTE_ORDER) + @staticmethod + def get_message_id_xstr(message): + """ + Returns request ID from packet in hex string + @param message: complete Diality Packet + @return:: integer with request ID + """ + msg_id = "" + for index in range(DenaliMessage.MSG_ID_INDEX, DenaliMessage.PAYLOAD_LENGTH_INDEX): + msg_id += "{0:02X}" .format(message['message'][index]) + return msg_id @staticmethod def get_payload_length(message): @@ -491,6 +502,7 @@ self.response_channel_id = -1 self.run = False self.sync_response_dictionary = {} + self.ui_received_function_ptr = None self.pending_requests = {} def start(self): @@ -634,18 +646,44 @@ self.send_event.set() # If it is not, this is a publication message and we need to call it's register function - elif dialin_ch_id in self.sync_response_dictionary.keys() and \ - dialin_msg_id in self.sync_response_dictionary[channel_id].keys(): - self.thread_pool_executor.submit( - self.sync_response_dictionary[dialin_ch_id][dialin_msg_id], - complete_dialin_message - ) + else: + if DenaliCanMessenger.is_ui_received_channel(dialin_ch_id): # check if the channel is in ui channels + if self.ui_received_function_ptr is not None: + self.thread_pool_executor.submit( + self.ui_received_function_ptr, + complete_dialin_message + ) + + if dialin_ch_id in self.sync_response_dictionary.keys() and \ + dialin_msg_id in self.sync_response_dictionary[channel_id].keys(): + self.thread_pool_executor.submit( + self.sync_response_dictionary[dialin_ch_id][dialin_msg_id], + complete_dialin_message + ) else: self.logger.critical("Invalid message: {}\n".format(self.messages)) # Done with this message, let's get the next one self.messages = None + @staticmethod + def is_ui_received_channel(channel_id: int) -> bool: + """ + checks if the channel id, channel_id is ui channel. + @param channel_id: the channel id to check + @return: true, if the channel is the ui channel. + """ + if channel_id in { + DenaliChannels.ui_to_hd_ch_id, + DenaliChannels.ui_to_dg_ch_id, + DenaliChannels.ui_to_dialin_ch_id, + DenaliChannels.ui_sync_broadcast_ch_id, + DenaliChannels.ui_alarm_broadcast_ch_id + }: # check if the channel is in ui channels + return True + else: + return False + def register_receiving_publication_function(self, channel_id, message_id, function): """ Assign a function with packet parameter to an sync request id, e.g., @@ -664,6 +702,16 @@ else: self.sync_response_dictionary[channel_id] = {message_id: function} + def register_received_all_ui_publication_function(self, function_ptr: Callable): + """ + Assign a function with packet parameter to an sync request id, e.g., + def function(packet). + + @param function_ptr: function reference + """ + + self.ui_received_function_ptr = function_ptr + def send(self, built_message: dict, time_out: float = DIALIN_MSG_RESP_TO, @@ -774,28 +822,43 @@ with open(filename, 'a') as f: f.write("{0}\n".format(packet)) - def do_console_out(self, complete_dialin_message: any) -> None: + @staticmethod + def convert_message_to_string(complete_dialin_message: dict) -> str: """ + Converts the DenaliMessage to hex string (data len is not hex) + @param complete_dialin_message: the complete can message in dictionary + @return: + """ + channel = "{0:03X}" .format(DenaliMessage.get_channel_id(complete_dialin_message)) + msg_id = DenaliMessage.get_message_id_xstr(complete_dialin_message) + data_len = DenaliMessage.get_payload_length(complete_dialin_message) + length = "{0:02X}" .format(data_len) + data = "" + pram_len = 0 + if data_len != 0: + pram_len = int(data_len / 4) + for i in range(pram_len): + data += "{0:02X}".format(complete_dialin_message['message'][DenaliMessage.PAYLOAD_START_INDEX + i ]) + data += "{0:02X}".format(complete_dialin_message['message'][DenaliMessage.PAYLOAD_START_INDEX + i + 1]) + data += "{0:02X}".format(complete_dialin_message['message'][DenaliMessage.PAYLOAD_START_INDEX + i + 2]) + data += "{0:02X}".format(complete_dialin_message['message'][DenaliMessage.PAYLOAD_START_INDEX + i + 3]) + data += " " + message = "{} {} {} {}".format(channel, msg_id, data_len, data) + return message + + @staticmethod + def do_console_out(complete_dialin_message: dict) -> None: + """ prints out the message in hex format similar to the candump - @param complete_dialin_message: the compele can bus message @return: None """ - print( - datetime.now().time(), - " " # can id - f"{(complete_dialin_message['channel_id']):0{3}X}" - " " # head tag - f"{(complete_dialin_message['message'][0]):0{2}X}" - " " # 2 bytes : seq - f"{(complete_dialin_message['message'][1]):0{2}X}" - f"{(complete_dialin_message['message'][2]):0{2}X}" - " " # 2 bytes : msg id - f"{(complete_dialin_message['message'][3]):0{2}X}" - f"{(complete_dialin_message['message'][4]):0{2}X}" - " " # 1 byte : len - f"{(complete_dialin_message['message'][5]):0{2}X}" - # TODO : add the payload here - # the complete message bytes listp - # , complete_dialin_message['message'] - ) + exception_msg_id = { + MsgIds.MSG_ID_UI_CHECK_IN.value, + MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK + } + msg_id = DenaliMessage.get_message_id(complete_dialin_message) + if msg_id in exception_msg_id: + return + message = "# " + DenaliCanMessenger.convert_message_to_string(complete_dialin_message) + print(message)