Index: scripts/base/base.py =================================================================== diff -u -rdd30a8caf586169db067d42da875a31507628e8d -ra8de2deaeffb523ed9d706a40726cc92c2a0edd2 --- scripts/base/base.py (.../base.py) (revision dd30a8caf586169db067d42da875a31507628e8d) +++ scripts/base/base.py (.../base.py) (revision a8de2deaeffb523ed9d706a40726cc92c2a0edd2) @@ -1,7 +1,25 @@ import os import shutil +from enum import Enum, unique + +class SWUpdateEnum(Enum): + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + +@unique +class SWUpdateTargets(SWUpdateEnum): + TARGET_TD = 0 + TARGET_TD_FPGA = 1 + TARGET_DD = 2 + TARGET_DD_FPGA = 3 + TARGET_RO = 4 + TARGET_RO_FPGA = 5 + NUM_OF_TARGETS = 6 + class Base: SW_UPDATE_FLASH_BUFFER_SIZE = 128 Index: scripts/update_package_script/update_package.py =================================================================== diff -u -r4e199a369c055fdad3866cebe7ef78b81035b4ba -ra8de2deaeffb523ed9d706a40726cc92c2a0edd2 --- scripts/update_package_script/update_package.py (.../update_package.py) (revision 4e199a369c055fdad3866cebe7ef78b81035b4ba) +++ scripts/update_package_script/update_package.py (.../update_package.py) (revision a8de2deaeffb523ed9d706a40726cc92c2a0edd2) @@ -1,12 +1,10 @@ import os -import can import re -from sphinx.util.osutil import getcwd +from scripts.base.base import Base, SWUpdateTargets +from scripts.update_package_script.utilities import Utilities, SWUpdateCommands -from scripts.base.base import Base - class SoftwareUpdateScript(Base): _DECODED_BYTES_KEY_NAME = 'decoded_bytes' @@ -15,7 +13,10 @@ _TOTAL_BYTES_TX_KEY_NAME = 'total_bytes_tx' _RESIDUAL_BYTES_KEY_NAME = 'residual_bytes' - _DECODE_LIST_MAX_SIZE_BYTES = 2048 + _XML_REPORT_FILE_TYPE_KEY_NAME = 'filetype' + _XML_REPORT_BIN_SIZE_KEY_NAME = 'size' + + _DECODE_LIST_MAX_SIZE_BYTES = 4096 _SHIFT_BITS_BY_8 = 8 _DECODE_COPRIME_1 = 19 _DECODE_COPRIME_2 = 23 @@ -24,16 +25,14 @@ _XML_REPORT_END_TAG = "" _XML_REPORT_HEADER_SIZE = 2 - _NUM_OF_BYTES_PER_CAN_FRAME = 8 - _CAN_INTERFACE = "can0" - def __init__(self): super().__init__() self._signature_start_in_bytes = bytes(self.SIGNATURE_START, 'utf-8') self._signature_end_in_bytes = bytes(self.SIGNATURE_END, 'utf-8') self._decode_data_status = dict() self._xml_report_values = dict() + self._utilities = Utilities() def _reset_variables(self): @@ -52,10 +51,10 @@ self._xml_report_values['name'] = '' self._xml_report_values['version'] = '' - self._xml_report_values['filetype'] = '' + self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] = '' self._xml_report_values['security'] = '' self._xml_report_values['version'] = '' - self._xml_report_values['size'] = '' + self._xml_report_values[self._XML_REPORT_BIN_SIZE_KEY_NAME] = 0 self._xml_report_values['raw'] = '' def _verify_signature(self, signature: bytes): @@ -97,7 +96,6 @@ self._decode_data_status['is_first_line'] = True for d in range(start_index, len(line_bytes)): - if self._decode_data_status['end_tag_found'] is False: decoded_value_bytes = (line_bytes[d] - self._decode_data_status[ 'decode_found_index']) % self._DECODE_VALUE @@ -108,12 +106,15 @@ converted_xml = self._decode_data_status['converted_xml'] self._decode_data_status['end_tag_found'] = True - self._xml_report_values['filetype'] = re.search('(.*)', converted_xml).group(1) - self._xml_report_values['size'] = re.search('(.*)', converted_xml).group(1) + self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] = \ + re.search('(.*)', converted_xml).group(1) + binary_size_int = re.search('(.*)', converted_xml).group(1) + self._xml_report_values[self._XML_REPORT_BIN_SIZE_KEY_NAME] = int(binary_size_int) + print(self._xml_report_values['filetype'], self._xml_report_values['size'], - len(converted_xml), converted_xml, self._decode_data_status['decode_found_index'], 'H') + len(converted_xml), converted_xml, self._decode_data_status['decode_found_index'], 'H') # TODO remove else: - self._decode_data_status[self._DECODED_BYTES_KEY_NAME].append(hex(line_bytes[d])) + self._decode_data_status[self._DECODED_BYTES_KEY_NAME].append(line_bytes[d]) self._decode_data_status[self._CUR_DATA_INDEX_KEY_NAME] += 1 def _process_read_line(self, line: bytes): @@ -131,7 +132,6 @@ self._decode_data_status[self._RESIDUAL_BYTES_KEY_NAME] = xml_report_start if self._decode_data_status['decode_values_found'] is True: - print(xml_report_start, len(xml_report_start), 'K') self._decode_line(xml_report_start) else: # TODO fill up @@ -140,9 +140,36 @@ self._get_decode_variables(line) if self._decode_data_status['decode_values_found'] is False else None self._decode_line(line) - def _send_update_data_to_bootloader(self): - pass + def _handle_processed_data(self): + if self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) == 0: # TODO these values should change to real return values + if self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] != '': + # TODO change the target right now they do not match because they are written for Leahi + # TODO for instance, it should be self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] as the second parameter + target = 'TARGET_TD' #self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] + target = SWUpdateTargets[target].value + self._utilities.send_command_msg(SWUpdateCommands.SW_UPDATE_START.value, target) + # TODO change the target right now they do not match because they are written for Leahi + elif self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) == -1: # TODO this should be changed to 1 but the ack is not received now yet + data_2_write = list() + current_index = self._decode_data_status[self._CUR_DATA_INDEX_KEY_NAME] + target = 'TARGET_TD' # self._xml_report_values[self._XML_REPORT_FILE_TYPE_KEY_NAME] + target = SWUpdateTargets[target].value + + if current_index % self.SW_UPDATE_FLASH_BUFFER_SIZE == 0: + data_2_write = self._decode_data_status[self._DECODED_BYTES_KEY_NAME] \ + [current_index - self.SW_UPDATE_FLASH_BUFFER_SIZE: current_index] + self._utilities.send_software_update_msg(target, data_2_write) + + elif current_index == self._xml_report_values[self._XML_REPORT_BIN_SIZE_KEY_NAME]: + binary_size = self._xml_report_values[self._XML_REPORT_BIN_SIZE_KEY_NAME] + data_2_write = self._decode_data_status[self._DECODED_BYTES_KEY_NAME][current_index - binary_size:] + data_2_write += [0] * (self.SW_UPDATE_FLASH_BUFFER_SIZE - binary_size) + + self._utilities.send_software_update_msg(target, data_2_write) + + #print(data_2_write, len(data_2_write), self._decode_data_status[self._DECODED_BYTES_KEY_NAME]) + def update_software_packages(self, packages_dir: str, stack_to_update: str = None): # 1. Verify signature # 2. Verify key @@ -160,11 +187,16 @@ self._reset_variables() for line in f: self._process_read_line(line) - self._send_update_data_to_bootloader() + self._handle_processed_data() + + self._handle_processed_data() f.close() + # TODO for testing remove print(self._decode_data_status[self._CUR_DATA_INDEX_KEY_NAME], self._decode_data_status[self._DECODED_BYTES_KEY_NAME][0], + self._decode_data_status[self._DECODED_BYTES_KEY_NAME][-4], self._decode_data_status[self._DECODED_BYTES_KEY_NAME][-3], self._decode_data_status[self._DECODED_BYTES_KEY_NAME][-2], - self._decode_data_status[self._DECODED_BYTES_KEY_NAME][-1]) + self._decode_data_status[self._DECODED_BYTES_KEY_NAME][-1], + len(self._decode_data_status[self._DECODED_BYTES_KEY_NAME])) # TODO remove Index: scripts/update_package_script/utilities.py =================================================================== diff -u --- scripts/update_package_script/utilities.py (revision 0) +++ scripts/update_package_script/utilities.py (revision a8de2deaeffb523ed9d706a40726cc92c2a0edd2) @@ -0,0 +1,169 @@ +import can +import struct +from time import sleep +from enum import unique +from can.interfaces.socketcan.socketcan import SocketcanBus +from scripts.base.base import Base, SWUpdateEnum, SWUpdateTargets + +@unique +class SWUpdateCommands(SWUpdateEnum): + SW_UPDATE_START = 0 + SW_UPDATE_ABORT = 1 + SW_UPDATE_RUN_APP = 2 + SW_UPDATE_VERIFY = 3 + NUM_OF_SW_UPDATE_CMDS = 4 + +class Utilities(Base): + + _CRC32_TABLE = ( + 0x00000000, 0x1EDC6F41, 0x3DB8DE82, 0x2364B1C3, 0x7B71BD04, 0x65ADD245, 0x46C96386, 0x58150CC7, + 0xF6E37A08, 0xE83F1549, 0xCB5BA48A, 0xD587CBCB, 0x8D92C70C, 0x934EA84D, 0xB02A198E, 0xAEF676CF, + 0xF31A9B51, 0xEDC6F410, 0xCEA245D3, 0xD07E2A92, 0x886B2655, 0x96B74914, 0xB5D3F8D7, 0xAB0F9796, + 0x05F9E159, 0x1B258E18, 0x38413FDB, 0x269D509A, 0x7E885C5D, 0x6054331C, 0x433082DF, 0x5DECED9E, + 0xF8E959E3, 0xE63536A2, 0xC5518761, 0xDB8DE820, 0x8398E4E7, 0x9D448BA6, 0xBE203A65, 0xA0FC5524, + 0x0E0A23EB, 0x10D64CAA, 0x33B2FD69, 0x2D6E9228, 0x757B9EEF, 0x6BA7F1AE, 0x48C3406D, 0x561F2F2C, + 0x0BF3C2B2, 0x152FADF3, 0x364B1C30, 0x28977371, 0x70827FB6, 0x6E5E10F7, 0x4D3AA134, 0x53E6CE75, + 0xFD10B8BA, 0xE3CCD7FB, 0xC0A86638, 0xDE740979, 0x866105BE, 0x98BD6AFF, 0xBBD9DB3C, 0xA505B47D, + 0xEF0EDC87, 0xF1D2B3C6, 0xD2B60205, 0xCC6A6D44, 0x947F6183, 0x8AA30EC2, 0xA9C7BF01, 0xB71BD040, + 0x19EDA68F, 0x0731C9CE, 0x2455780D, 0x3A89174C, 0x629C1B8B, 0x7C4074CA, 0x5F24C509, 0x41F8AA48, + 0x1C1447D6, 0x02C82897, 0x21AC9954, 0x3F70F615, 0x6765FAD2, 0x79B99593, 0x5ADD2450, 0x44014B11, + 0xEAF73DDE, 0xF42B529F, 0xD74FE35C, 0xC9938C1D, 0x918680DA, 0x8F5AEF9B, 0xAC3E5E58, 0xB2E23119, + 0x17E78564, 0x093BEA25, 0x2A5F5BE6, 0x348334A7, 0x6C963860, 0x724A5721, 0x512EE6E2, 0x4FF289A3, + 0xE104FF6C, 0xFFD8902D, 0xDCBC21EE, 0xC2604EAF, 0x9A754268, 0x84A92D29, 0xA7CD9CEA, 0xB911F3AB, + 0xE4FD1E35, 0xFA217174, 0xD945C0B7, 0xC799AFF6, 0x9F8CA331, 0x8150CC70, 0xA2347DB3, 0xBCE812F2, + 0x121E643D, 0x0CC20B7C, 0x2FA6BABF, 0x317AD5FE, 0x696FD939, 0x77B3B678, 0x54D707BB, 0x4A0B68FA, + 0xC0C1D64F, 0xDE1DB90E, 0xFD7908CD, 0xE3A5678C, 0xBBB06B4B, 0xA56C040A, 0x8608B5C9, 0x98D4DA88, + 0x3622AC47, 0x28FEC306, 0x0B9A72C5, 0x15461D84, 0x4D531143, 0x538F7E02, 0x70EBCFC1, 0x6E37A080, + 0x33DB4D1E, 0x2D07225F, 0x0E63939C, 0x10BFFCDD, 0x48AAF01A, 0x56769F5B, 0x75122E98, 0x6BCE41D9, + 0xC5383716, 0xDBE45857, 0xF880E994, 0xE65C86D5, 0xBE498A12, 0xA095E553, 0x83F15490, 0x9D2D3BD1, + 0x38288FAC, 0x26F4E0ED, 0x0590512E, 0x1B4C3E6F, 0x435932A8, 0x5D855DE9, 0x7EE1EC2A, 0x603D836B, + 0xCECBF5A4, 0xD0179AE5, 0xF3732B26, 0xEDAF4467, 0xB5BA48A0, 0xAB6627E1, 0x88029622, 0x96DEF963, + 0xCB3214FD, 0xD5EE7BBC, 0xF68ACA7F, 0xE856A53E, 0xB043A9F9, 0xAE9FC6B8, 0x8DFB777B, 0x9327183A, + 0x3DD16EF5, 0x230D01B4, 0x0069B077, 0x1EB5DF36, 0x46A0D3F1, 0x587CBCB0, 0x7B180D73, 0x65C46232, + 0x2FCF0AC8, 0x31136589, 0x1277D44A, 0x0CABBB0B, 0x54BEB7CC, 0x4A62D88D, 0x6906694E, 0x77DA060F, + 0xD92C70C0, 0xC7F01F81, 0xE494AE42, 0xFA48C103, 0xA25DCDC4, 0xBC81A285, 0x9FE51346, 0x81397C07, + 0xDCD59199, 0xC209FED8, 0xE16D4F1B, 0xFFB1205A, 0xA7A42C9D, 0xB97843DC, 0x9A1CF21F, 0x84C09D5E, + 0x2A36EB91, 0x34EA84D0, 0x178E3513, 0x09525A52, 0x51475695, 0x4F9B39D4, 0x6CFF8817, 0x7223E756, + 0xD726532B, 0xC9FA3C6A, 0xEA9E8DA9, 0xF442E2E8, 0xAC57EE2F, 0xB28B816E, 0x91EF30AD, 0x8F335FEC, + 0x21C52923, 0x3F194662, 0x1C7DF7A1, 0x02A198E0, 0x5AB49427, 0x4468FB66, 0x670C4AA5, 0x79D025E4, + 0x243CC87A, 0x3AE0A73B, 0x198416F8, 0x075879B9, 0x5F4D757E, 0x41911A3F, 0x62F5ABFC, 0x7C29C4BD, + 0xD2DFB272, 0xCC03DD33, 0xEF676CF0, 0xF1BB03B1, 0xA9AE0F76, 0xB7726037, 0x9416D1F4, 0x8ACABEB5, + ) + + _SHIFT_8_BITS_FOR_BYTE_SHIFT = 8 + _SHIFT_24_BITS = 24 + _SHIFT_BITS_BY_A_NIBBLE = 4 + + _NUM_OF_BYTES_PER_CAN_FRAME = 8 + _CAN_INTERFACE = "can0" + _SEND_CMD_MAIL_BOX = 0x601 + _RESP_CMD_MAIL_BOX = 0x606 + + SEND_MSG_ACK_STATUS_KEY_NAME = 'cmd' + UPDATE_MSG_ACK_STATUS_KEY_NAME = 'update' + + def __init__(self): + + super().__init__() + self._can_bus = SocketcanBus(channel=self._CAN_INTERFACE) + self._msg_id_count = 0 + self._msg_sw_update_index = 0 + self._update_mail_boxes = self._prepare_update_mail_boxes() + self._msg_ack_nack_status = dict() + + self._msg_ack_nack_status[self.SEND_MSG_ACK_STATUS_KEY_NAME] = 0 + self._msg_ack_nack_status[self.UPDATE_MSG_ACK_STATUS_KEY_NAME] = 0 + + def get_msg_ack_nack_status(self, msg_type: str): + return self._msg_ack_nack_status[msg_type] + + def clear_msg_ack_nack_status(self, msg_type: str): + self._msg_ack_nack_status[msg_type] = 0 + + def send_command_msg(self, cmd: int, target: int): + + can_frame = list() + can_frame_bytes = b'' + self._msg_id_count += 1 + can_frame.append(struct.pack('B', self._msg_id_count)) + cmd_combo = (target << self._SHIFT_BITS_BY_A_NIBBLE) | (cmd & 0xF) + can_frame.append(struct.pack('B', cmd_combo)) + random_value = 0 # In case cybersecurity was needed + random_value = struct.pack('H', random_value) + can_frame.append(random_value) + can_frame_bytes += b''.join(can_frame) + print(can_frame, can_frame_bytes) + crc_32 = 0 #self._get_crc32(can_frame_bytes) # TODO what is wrong with this? + can_frame.append(struct.pack('I', crc_32)) + can_frame_bytes = b''.join(can_frame) + packet = can.Message(arbitration_id=self._SEND_CMD_MAIL_BOX, data=can_frame_bytes, is_extended_id=False) + self._can_bus.send(packet, 0) + + message = self._can_bus.recv(0.5) #TODO is this good? change it + self._msg_ack_nack_status[self.SEND_MSG_ACK_STATUS_KEY_NAME] = -1 if message is None else 1 + print(self._msg_ack_nack_status) + + def send_software_update_msg(self, target: int, data: list): + mail_box = self._update_mail_boxes[target] + can_frame = list() + can_msg_bytes = b'' + can_frame_bytes = b'' + self._msg_id_count += 1 + can_frame.append(struct.pack('B', self._msg_id_count)) + can_frame.append(struct.pack('B', target)) + self._msg_sw_update_index += 1 + can_frame.append(struct.pack('H', self._msg_sw_update_index)) + can_msg_bytes += b''.join(can_frame) + crc_32 = 0 #self._get_crc32(can_frame_bytes) # TODO what is wrong with this? + can_frame.append(struct.pack('I', crc_32)) + can_msg_bytes = b''.join(can_frame) + test = list() + for b in data: + test.append(struct.pack('B', b)) + can_msg_bytes += b''.join(test) + print(len(can_msg_bytes), can_msg_bytes, len(data)) + + for byte in can_msg_bytes: + can_frame_bytes += bytes([byte]) + if can_msg_bytes.index(byte) % 8 == 0 and can_msg_bytes.index(byte) != 0: + + packet = can.Message(arbitration_id=mail_box, data=can_frame_bytes, is_extended_id=False) + print(can_frame_bytes, mail_box, packet, len(can_frame_bytes), can_msg_bytes.index(byte)) + self._can_bus.send(packet, 0) + sleep(0.1) + # TODO send the message + can_frame_bytes = b'' + + + + + #print(data, len(data), can_frame_bytes) + + @classmethod + def _get_crc32(cls, data): + + crc = 0 + length = len(data) + i = 0 + + while length > 0: + print(i, length, crc, data[i], data[i] ^ (crc >> cls._SHIFT_24_BITS)) + crc = (crc << cls._SHIFT_8_BITS_FOR_BYTE_SHIFT) ^ cls._CRC32_TABLE[data[i] ^ (crc >> cls._SHIFT_24_BITS)] + i += 1 + length -= 1 + + return crc + + @staticmethod + def _prepare_update_mail_boxes(): + + temp = dict() + temp[SWUpdateTargets.TARGET_TD.value] = 0x602 + temp[SWUpdateTargets.TARGET_TD_FPGA.value] = 0x602 + temp[SWUpdateTargets.TARGET_DD.value] = 0x603 + temp[SWUpdateTargets.TARGET_DD_FPGA.value] = 0x603 + temp[SWUpdateTargets.TARGET_RO.value] = 0x604 + temp[SWUpdateTargets.TARGET_RO_FPGA.value] = 0x604 + + return temp +