Index: dialin/protocols/CAN.py =================================================================== diff -u -r68e6f7c82ebb25658b4fecece474c2640a6dff87 -r9e5d155f34e07be6888bcaa55878f6639abd150a --- dialin/protocols/CAN.py (.../CAN.py) (revision 68e6f7c82ebb25658b4fecece474c2640a6dff87) +++ dialin/protocols/CAN.py (.../CAN.py) (revision 9e5d155f34e07be6888bcaa55878f6639abd150a) @@ -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) Index: dialin/ui/hd_simulator.py =================================================================== diff -u -ra8510e633918aee619a1383b97ec371b2c853099 -r9e5d155f34e07be6888bcaa55878f6639abd150a --- dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision a8510e633918aee619a1383b97ec371b2c853099) +++ dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision 9e5d155f34e07be6888bcaa55878f6639abd150a) @@ -16,7 +16,7 @@ import enum from time import sleep from typing import Callable - +from inspect import signature from . import messageBuilder from ..common import * from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels @@ -123,6 +123,29 @@ message_id, function_ptr)) + def set_ui_all_publication(self, function_ptr: Callable) -> None: + """ + Allows later addition of publication to the HDSimulator + This function needs improvements, it has been implemented to quickly being used by Development Testing team. + @param function_ptr: (Callable) the pointer to the message handler function + @return: None + """ + function_signature_exp = "(message:dict)->None" # TODO: update later to get param name and type. + if not callable(function_ptr): + print("ui all publication rejected (not a function)") + self.logger.debug("ui all publication rejected (not a function)") + else: + function_signature_act = str(signature(function_ptr)).replace(" ", "") + if function_signature_act == function_signature_exp: + self.can_interface.register_received_all_ui_publication_function(function_ptr) + else: + print("ui all publication rejected {0},{1}" + .format(function_signature_exp, + function_signature_act)) + self.logger.debug("rejected ui all messages publication registration, expected function signature {0}, got {1} " + .format(function_signature_exp, + function_signature_act)) + def get_ui_version(self): """ Gets the ui version @@ -2089,16 +2112,16 @@ @return: None """ - payload = unsigned_to_bytearray(blood_leak_status) - payload += unsigned_to_bytearray(blood_leak_state) - payload += unsigned_to_bytearray(blood_leak_zero_status_counter) - payload += unsigned_to_bytearray(blood_leak_counter) - payload += unsigned_to_bytearray(blood_leak_zeroed_status) - payload += unsigned_to_bytearray(blood_leak_detect_set_point) - payload += unsigned_to_bytearray(blood_leak_detect_level) - payload += unsigned_to_bytearray(blood_leak_st_count) - payload += unsigned_to_bytearray(blood_leak_led_intensity) - payload += unsigned_to_bytearray(blood_leak_register_counter) + payload = unsigned_integer_to_bytearray(blood_leak_status) + payload += unsigned_integer_to_bytearray(blood_leak_state) + payload += unsigned_integer_to_bytearray(blood_leak_zero_status_counter) + payload += unsigned_integer_to_bytearray(blood_leak_counter) + payload += unsigned_integer_to_bytearray(blood_leak_zeroed_status) + payload += unsigned_integer_to_bytearray(blood_leak_detect_set_point) + payload += unsigned_integer_to_bytearray(blood_leak_detect_level) + payload += unsigned_integer_to_bytearray(blood_leak_st_count) + payload += unsigned_integer_to_bytearray(blood_leak_led_intensity) + payload += unsigned_integer_to_bytearray(blood_leak_register_counter) message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, message_id=MsgIds.MSG_ID_HD_BLOOD_LEAK_DATA.value, @@ -2114,8 +2137,8 @@ @return: None """ - payload = unsigned_to_bytearray(lower_level) - payload += unsigned_to_bytearray(upper_level) + payload = unsigned_integer_to_bytearray(lower_level) + payload += unsigned_integer_to_bytearray(upper_level) message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, message_id=MsgIds.MSG_ID_HD_AIR_TRAP_DATA.value, @@ -2131,8 +2154,8 @@ @return: None """ - payload = unsigned_to_bytearray(venous_air_bubble_status) - payload += unsigned_to_bytearray(venous_air_bubble_state) + payload = unsigned_integer_to_bytearray(venous_air_bubble_status) + payload += unsigned_integer_to_bytearray(venous_air_bubble_state) message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, message_id=MsgIds.MSG_ID_HD_BUBBLES_DATA.value, Index: dialin/ui/hd_simulator_alarms.py =================================================================== diff -u -r3a70bfb451b74106348c064c34f19934aadd9119 -r9e5d155f34e07be6888bcaa55878f6639abd150a --- dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision 3a70bfb451b74106348c064c34f19934aadd9119) +++ dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision 9e5d155f34e07be6888bcaa55878f6639abd150a) @@ -20,7 +20,7 @@ from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels from logging import Logger from ..utils.base import AbstractSubSystem -from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from ..utils.conversions import * from ..common.msg_defs import MsgIds, MsgFieldPositions from ..common.alarm_defs import AlarmList from dialin.common.prs_defs import AlarmDataTypes @@ -364,7 +364,8 @@ self.can_interface.send(message, 0) def cmd_set_alarm_triggered(self, alarm_id, field_descriptor_1: int, data_field_1: str, - field_descriptor_2: int, data_field_2: str) -> None: + field_descriptor_2: int, data_field_2: str, + priority: int, rank: int, clear_top: int) -> None: """ Triggers an alarm. @@ -377,6 +378,10 @@ @param data_field_1: alarm data 1 @param field_descriptor_2: alarm data 2 type @param data_field_2: alarm data 2 + @param priority: alarm priority + @param rank: alarm rank + @param clear_top: clear top only + @return: None """ zero = integer_to_bytearray(0) @@ -404,6 +409,10 @@ payload += integer_to_bytearray(field_descriptor_2) payload += integer_to_bytearray(int(data_field_2)) + payload += unsigned_integer_to_bytearray(priority) + payload += unsigned_integer_to_bytearray(rank) + payload += unsigned_integer_to_bytearray(clear_top) + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_alarm_broadcast_ch_id, message_id=MsgIds.MSG_ID_ALARM_TRIGGERED.value, payload=payload)