From 26dd5b6e59db50ed6762246bb32dd20d6cf6ef2d Mon Sep 17 00:00:00 2001 From: shayana18 Date: Sat, 5 Apr 2025 19:02:44 -0700 Subject: [PATCH 1/6] initial run --- boards.py | 9 +++++++++ bootloader.py | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/boards.py b/boards.py index d995179..ae43f11 100644 --- a/boards.py +++ b/boards.py @@ -35,6 +35,7 @@ class Board: name: str start_update_can_id: int update_ack_can_id: int + boot_load_bin_can_id : int mcu: Microcontroller path: str @@ -97,6 +98,7 @@ class Board: name="VC", start_update_can_id=1210, update_ack_can_id=1211, + boot_load_bin_can_id=500, mcu=STM32H733_MCU, path=os.path.join("firmware", "quadruna", "VC", "quadruna_VC_app_metadata.hex"), ) @@ -104,6 +106,7 @@ class Board: name="BMS", start_update_can_id=1200, update_ack_can_id=1201, + boot_load_bin_can_id=400, mcu=STM32H733_MCU, path=os.path.join("firmware", "quadruna", "BMS", "quadruna_BMS_app_metadata.hex"), ) @@ -111,6 +114,7 @@ class Board: name="FSM", start_update_can_id=1220, update_ack_can_id=1221, + boot_load_bin_can_id=600, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "FSM", "quadruna_FSM_app_metadata.hex"), ) @@ -118,6 +122,7 @@ class Board: name="RSM", start_update_can_id=1230, update_ack_can_id=1231, + boot_load_bin_can_id=700, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "RSM", "quadruna_RSM_app_metadata.hex"), ) @@ -125,6 +130,7 @@ class Board: name="CRIT", start_update_can_id=1240, update_ack_can_id=1241, + boot_load_bin_can_id=900, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "CRIT", "quadruna_CRIT_app_metadata.hex"), ) @@ -132,10 +138,13 @@ class Board: name="h7dev", start_update_can_id=1300, update_ack_can_id=1301, + boot_load_bin_can_id=2000, # random number.... NEEDS TO BE CORRECTED mcu=STM32H733_MCU, path=os.path.join("firmware", "dev", "h7dev", "h7dev_app_metadata.hex"), ) +#TODO: add DAM board config + CONFIGS = { "VC": [quadruna_VC], "BMS": [quadruna_BMS], diff --git a/bootloader.py b/bootloader.py index dec3831..4191f2c 100644 --- a/bootloader.py +++ b/bootloader.py @@ -34,6 +34,9 @@ # The minimum amount of data the microcontroller can program at a time. MIN_PROG_SIZE_BYTES = 32 +ALL_PACKETS_VALID = 0xFFFFFFFFFFFFFFFF +WINDOW_SIZE = 64 + class Bootloader: def __init__( @@ -49,6 +52,7 @@ def __init__( self.board = board self.timeout = timeout self.ui_callback = ui_callback + self.dropped_packets = set() def start_update(self) -> bool: """ @@ -123,21 +127,53 @@ def program(self) -> None: Program the binary into flash. There is no CAN handshake here to reduce latency during programming. Also, the bootloader will verify the app's code is valid by computing a checksum. - """ + + # updated changes: built a TCP sequence number inspired packet validity checker. Essentially we have 64 of CAN IDs for each board + # reserved for bootloading. These can ids represent sequential ids for each packet in a 64 packet window. On the board side, the board expects a + # specific can id (starts with 1 and increments up to 64) if it matches then the board sets the respective bit in its return message (1 packet (1 indexed) = 0th bit (0 indexed)) + # after 64 packets it returns a 64 bit message describing if the packet was recieved correctly (1 = yes, 0 = no). Based on this message we can populate a set containing a + # tuple (address, msg) after our first tranmission if the set of missed packets is not empty we send a START_RETRANSMISSION MESSAGE which expects sequential CAN ids within the same 1-64 range + # however, now for each packet we do not slide our window until a packet has been acked and each packet will have a returned ack status back in comparison to the earlier 64 packs + # this will continue until the set is empty and then send an end tranmission message + + packet_in_window_index = 0 + + def _validator(msg: can.Message): + "Validate that mem was programmed successfully" + print(f"can id is {msg.arbitration_id}") + if msg.arbitration_id == (self.board.boot_load_bin_can_id + WINDOW_SIZE) and msg.data == ALL_PACKETS_VALID: + return True + + status_msg_int = int.from_bytes(msg.data, byteorder="little") + dropped_packets_pos = ALL_PACKETS_VALID ^ status_msg_int # this will set create a mask where all the dropped backet positions are 1 and not dropped are 0 + + for pos in range(WINDOW_SIZE): + if dropped_packets_pos & (1 << pos) != 0: + # since we increment memory address by 8 bytes at a time and we know that our current address is pointing to the highest 8-byte associated to the window + # we want to save the address assocaited to this particular message + self.dropped_packets.add(address - (WINDOW_SIZE - pos) * 8) + print(f"Address is {address}\n") + print(f"Packet dropped associated to bin address {address - (WINDOW_SIZE - pos) * 8}\n") #debugging + return True # defaulting to true for debugging + for i, address in enumerate( range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) ): if self.ui_callback and i % 128 == 0: self.ui_callback("Programming data", self.size_bytes(), i * 8) - data = [self.ih[address + i] for i in range(0, 8)] + self.bus.send( can.Message( - arbitration_id=PROGRAM_CAN_ID, data=data, is_extended_id=False + arbitration_id=self.board.boot_load_bin_can_id + packet_in_window_index, data=data, is_extended_id=False ) ) + if packet_in_window_index == WINDOW_SIZE - 1: + if not self._await_can_msg(validator=_validator, timeout=self.timeout): + return False + packet_in_window_index = (packet_in_window_index + 1) % WINDOW_SIZE # Empirically, this tiny delay between messages seems to improve reliability. time.sleep(0.0005) @@ -177,7 +213,6 @@ def update(self) -> None: Run the update procedure for this bootloader. """ - def _intersect(a_min, a_max, b_min, b_max): """1-D intersection to check if an app's hex and a flash sector share any addresses.""" return a_max >= b_min and b_max >= a_min @@ -295,4 +330,4 @@ def size_bytes(self) -> int: return int( math.ceil((self.ih.maxaddr() - self.ih.minaddr()) / MIN_PROG_SIZE_BYTES) * MIN_PROG_SIZE_BYTES - ) + ) \ No newline at end of file From 2d0e16a348e61c5149d90b795cbe6ec1d4bac206 Mon Sep 17 00:00:00 2001 From: shayana18 Date: Sun, 13 Apr 2025 00:02:53 -0700 Subject: [PATCH 2/6] In progress changes --- bootloader.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/bootloader.py b/bootloader.py index 4191f2c..72ae18d 100644 --- a/bootloader.py +++ b/bootloader.py @@ -142,20 +142,21 @@ def program(self) -> None: def _validator(msg: can.Message): "Validate that mem was programmed successfully" print(f"can id is {msg.arbitration_id}") - if msg.arbitration_id == (self.board.boot_load_bin_can_id + WINDOW_SIZE) and msg.data == ALL_PACKETS_VALID: - return True + # if msg.arbitration_id == (self.board.boot_load_bin_can_id + WINDOW_SIZE) and msg.data == ALL_PACKETS_VALID: + # return True - status_msg_int = int.from_bytes(msg.data, byteorder="little") - dropped_packets_pos = ALL_PACKETS_VALID ^ status_msg_int # this will set create a mask where all the dropped backet positions are 1 and not dropped are 0 - - for pos in range(WINDOW_SIZE): - if dropped_packets_pos & (1 << pos) != 0: - # since we increment memory address by 8 bytes at a time and we know that our current address is pointing to the highest 8-byte associated to the window - # we want to save the address assocaited to this particular message - self.dropped_packets.add(address - (WINDOW_SIZE - pos) * 8) - print(f"Address is {address}\n") - print(f"Packet dropped associated to bin address {address - (WINDOW_SIZE - pos) * 8}\n") #debugging - return True # defaulting to true for debugging + # status_msg_int = int.from_bytes(msg.data, byteorder="little") + # dropped_packets_pos = ALL_PACKETS_VALID ^ status_msg_int # this will set create a mask where all the dropped backet positions are 1 and not dropped are 0 + # print(f"{}") + + # for pos in range(WINDOW_SIZE): + # if dropped_packets_pos & (1 << pos) != 0: + # # since we increment memory address by 8 bytes at a time and we know that our current address is pointing to the highest 8-byte associated to the window + # # we want to save the address assocaited to this particular message + # self.dropped_packets.add(address - (WINDOW_SIZE - pos) * 8) + # print(f"Address is {address}\n") + # print(f"Packet dropped associated to bin address {address - (WINDOW_SIZE - pos) * 8}\n") #debugging + # return True # defaulting to true for debugging for i, address in enumerate( range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) @@ -164,14 +165,15 @@ def _validator(msg: can.Message): self.ui_callback("Programming data", self.size_bytes(), i * 8) data = [self.ih[address + i] for i in range(0, 8)] + print(f"Sent Can Id: {self.board.boot_load_bin_can_id + packet_in_window_index}") self.bus.send( can.Message( arbitration_id=self.board.boot_load_bin_can_id + packet_in_window_index, data=data, is_extended_id=False ) ) - if packet_in_window_index == WINDOW_SIZE - 1: - if not self._await_can_msg(validator=_validator, timeout=self.timeout): - return False + # if packet_in_window_index == WINDOW_SIZE - 1: + # if not self._await_can_msg(validator=_validator, timeout=self.timeout): + # return False packet_in_window_index = (packet_in_window_index + 1) % WINDOW_SIZE # Empirically, this tiny delay between messages seems to improve reliability. From 7a20986f15c8f36b4ffdd0a0301c53cec96409f4 Mon Sep 17 00:00:00 2001 From: shayana18 Date: Tue, 6 May 2025 22:52:59 -0700 Subject: [PATCH 3/6] more changes. Transmission working, however if a packet is dropped every packet is dropped --- boards.py | 16 +++++++--------- bootloader.py | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/boards.py b/boards.py index ae43f11..68813a2 100644 --- a/boards.py +++ b/boards.py @@ -35,7 +35,7 @@ class Board: name: str start_update_can_id: int update_ack_can_id: int - boot_load_bin_can_id : int + boot_load_bin_can_id : int mcu: Microcontroller path: str @@ -98,7 +98,7 @@ class Board: name="VC", start_update_can_id=1210, update_ack_can_id=1211, - boot_load_bin_can_id=500, + boot_load_bin_can_id = 500, mcu=STM32H733_MCU, path=os.path.join("firmware", "quadruna", "VC", "quadruna_VC_app_metadata.hex"), ) @@ -106,7 +106,7 @@ class Board: name="BMS", start_update_can_id=1200, update_ack_can_id=1201, - boot_load_bin_can_id=400, + boot_load_bin_can_id = 400, mcu=STM32H733_MCU, path=os.path.join("firmware", "quadruna", "BMS", "quadruna_BMS_app_metadata.hex"), ) @@ -114,7 +114,7 @@ class Board: name="FSM", start_update_can_id=1220, update_ack_can_id=1221, - boot_load_bin_can_id=600, + boot_load_bin_can_id = 600, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "FSM", "quadruna_FSM_app_metadata.hex"), ) @@ -122,7 +122,7 @@ class Board: name="RSM", start_update_can_id=1230, update_ack_can_id=1231, - boot_load_bin_can_id=700, + boot_load_bin_can_id = 700, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "RSM", "quadruna_RSM_app_metadata.hex"), ) @@ -130,7 +130,7 @@ class Board: name="CRIT", start_update_can_id=1240, update_ack_can_id=1241, - boot_load_bin_can_id=900, + boot_load_bin_can_id = 900, mcu=STM32F412_MCU, path=os.path.join("firmware", "quadruna", "CRIT", "quadruna_CRIT_app_metadata.hex"), ) @@ -138,13 +138,11 @@ class Board: name="h7dev", start_update_can_id=1300, update_ack_can_id=1301, - boot_load_bin_can_id=2000, # random number.... NEEDS TO BE CORRECTED + boot_load_bin_can_id = 300, mcu=STM32H733_MCU, path=os.path.join("firmware", "dev", "h7dev", "h7dev_app_metadata.hex"), ) -#TODO: add DAM board config - CONFIGS = { "VC": [quadruna_VC], "BMS": [quadruna_BMS], diff --git a/bootloader.py b/bootloader.py index 72ae18d..d9f66b7 100644 --- a/bootloader.py +++ b/bootloader.py @@ -37,6 +37,7 @@ ALL_PACKETS_VALID = 0xFFFFFFFFFFFFFFFF WINDOW_SIZE = 64 +BOARD_10HZ_STATUS_ID = [1309, 1209, 1249, 1229, 1239, 1219] class Bootloader: def __init__( @@ -140,24 +141,28 @@ def program(self) -> None: packet_in_window_index = 0 def _validator(msg: can.Message): - "Validate that mem was programmed successfully" - print(f"can id is {msg.arbitration_id}") - # if msg.arbitration_id == (self.board.boot_load_bin_can_id + WINDOW_SIZE) and msg.data == ALL_PACKETS_VALID: - # return True + # Ignore all known status messages + print(f"Can ID that come through {msg.arbitration_id}\n") + if msg.arbitration_id in BOARD_10HZ_STATUS_ID: + return None # Not relevant, keep waiting - # status_msg_int = int.from_bytes(msg.data, byteorder="little") - # dropped_packets_pos = ALL_PACKETS_VALID ^ status_msg_int # this will set create a mask where all the dropped backet positions are 1 and not dropped are 0 - # print(f"{}") - - # for pos in range(WINDOW_SIZE): - # if dropped_packets_pos & (1 << pos) != 0: - # # since we increment memory address by 8 bytes at a time and we know that our current address is pointing to the highest 8-byte associated to the window - # # we want to save the address assocaited to this particular message - # self.dropped_packets.add(address - (WINDOW_SIZE - pos) * 8) - # print(f"Address is {address}\n") - # print(f"Packet dropped associated to bin address {address - (WINDOW_SIZE - pos) * 8}\n") #debugging - # return True # defaulting to true for debugging + status_msg_int = int.from_bytes(msg.data, byteorder="little") + expectedID = self.board.boot_load_bin_can_id + WINDOW_SIZE + + if msg.arbitration_id == expectedID and status_msg_int == ALL_PACKETS_VALID: + print(f"this was hit\n status message back{status_msg_int}\n") + return True + else: + dropped_mask = ALL_PACKETS_VALID ^ status_msg_int + for pos in range(WINDOW_SIZE): + if dropped_mask & (1 << pos): + # Calculate dropped address + dropped_address = expectedID - (WINDOW_SIZE - pos) * 8 + self.dropped_packets.add(dropped_address) + print(f"number of dropped packets {len(self.dropped_packets)}\n") + return True # Still a valid response, even if not perfect + for i, address in enumerate( range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) ): @@ -165,15 +170,14 @@ def _validator(msg: can.Message): self.ui_callback("Programming data", self.size_bytes(), i * 8) data = [self.ih[address + i] for i in range(0, 8)] - print(f"Sent Can Id: {self.board.boot_load_bin_can_id + packet_in_window_index}") self.bus.send( can.Message( arbitration_id=self.board.boot_load_bin_can_id + packet_in_window_index, data=data, is_extended_id=False ) ) - # if packet_in_window_index == WINDOW_SIZE - 1: - # if not self._await_can_msg(validator=_validator, timeout=self.timeout): - # return False + if packet_in_window_index == WINDOW_SIZE - 1: + if not self._await_can_msg(validator=_validator, timeout=self.timeout): + return False packet_in_window_index = (packet_in_window_index + 1) % WINDOW_SIZE # Empirically, this tiny delay between messages seems to improve reliability. From 14c9c619b873851e455ad25f25ed9b965eca6d66 Mon Sep 17 00:00:00 2001 From: shayana18 Date: Sat, 17 May 2025 14:56:16 -0700 Subject: [PATCH 4/6] NAK implemented, needs to be tested --- bootloader.py | 64 ++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/bootloader.py b/bootloader.py index d9f66b7..8d65179 100644 --- a/bootloader.py +++ b/bootloader.py @@ -20,6 +20,9 @@ PROGRAM_CAN_ID = 1001 VERIFY_CAN_ID = 1002 +NAK_ID = 0 +NAK_TIMEOUT = 0.1 + # CAN reply message IDs. ERASE_SECTOR_COMPLETE_CAN_ID = 1010 APP_VALIDITY_CAN_ID = 1011 @@ -54,6 +57,7 @@ def __init__( self.timeout = timeout self.ui_callback = ui_callback self.dropped_packets = set() + self.__transmission_address = 0 def start_update(self) -> bool: """ @@ -130,56 +134,44 @@ def program(self) -> None: by computing a checksum. """ - # updated changes: built a TCP sequence number inspired packet validity checker. Essentially we have 64 of CAN IDs for each board - # reserved for bootloading. These can ids represent sequential ids for each packet in a 64 packet window. On the board side, the board expects a - # specific can id (starts with 1 and increments up to 64) if it matches then the board sets the respective bit in its return message (1 packet (1 indexed) = 0th bit (0 indexed)) - # after 64 packets it returns a 64 bit message describing if the packet was recieved correctly (1 = yes, 0 = no). Based on this message we can populate a set containing a - # tuple (address, msg) after our first tranmission if the set of missed packets is not empty we send a START_RETRANSMISSION MESSAGE which expects sequential CAN ids within the same 1-64 range - # however, now for each packet we do not slide our window until a packet has been acked and each packet will have a returned ack status back in comparison to the earlier 64 packs - # this will continue until the set is empty and then send an end tranmission message - - packet_in_window_index = 0 - + # updated TCP inspired can bootloading: sender will send packet with can id's representing their memory address. The reciever will expect a can ID, of the sender can ID and reciever can ID match all is good, if there is a miss match the board will transmit the excepted can ID back. + # if the expected Can ID is a multiple of 4 it will directly be sent back to the user to begin retransmission at that address, if it is not an interval of 4 then retransmision is restarted at the closests (smaller) interval of 4. Note that a nuiassnace that we have to figure out is that + # if we do want to move back to the closest interval of 4 then we need to figure out how to reflash adddresses that were already flashed (ie if its address 247 and the closest interval of 4 is 244) then we will attempt to reflash 244-246 even though they have already been flashed. Now with the + # stm32s to write to flash memory we need to first erase it. Now if that is the case we need to figure out how to erase as the stm32 can only erase sectors at a time which is 16kb.... I am unsure on what happens if we try to flash memory that has not been erased. If it retains its originally value that that would be best and we can jsut do redundant flashing until we + # get to the address that actually needs to be reflashed. + def _validator(msg: can.Message): # Ignore all known status messages print(f"Can ID that come through {msg.arbitration_id}\n") - if msg.arbitration_id in BOARD_10HZ_STATUS_ID: - return None # Not relevant, keep waiting - - status_msg_int = int.from_bytes(msg.data, byteorder="little") - expectedID = self.board.boot_load_bin_can_id + WINDOW_SIZE - - if msg.arbitration_id == expectedID and status_msg_int == ALL_PACKETS_VALID: - print(f"this was hit\n status message back{status_msg_int}\n") - return True + if msg.arbitration_id == NAK_ID: + self.__transmission_address = int.from_bytes(msg.data, "little") + return False else: - dropped_mask = ALL_PACKETS_VALID ^ status_msg_int - for pos in range(WINDOW_SIZE): - if dropped_mask & (1 << pos): - # Calculate dropped address - dropped_address = expectedID - (WINDOW_SIZE - pos) * 8 - self.dropped_packets.add(dropped_address) - print(f"number of dropped packets {len(self.dropped_packets)}\n") - return True # Still a valid response, even if not perfect - - - for i, address in enumerate( + return True + + for i, self.__transmission_address in enumerate( range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) ): if self.ui_callback and i % 128 == 0: self.ui_callback("Programming data", self.size_bytes(), i * 8) - data = [self.ih[address + i] for i in range(0, 8)] + data = [self.ih[self.__transmission_address + i] for i in range(0, 8)] self.bus.send( can.Message( - arbitration_id=self.board.boot_load_bin_can_id + packet_in_window_index, data=data, is_extended_id=False + arbitration_id= self.__transmission_address, data=data, is_extended_id=False ) ) - if packet_in_window_index == WINDOW_SIZE - 1: - if not self._await_can_msg(validator=_validator, timeout=self.timeout): - return False - packet_in_window_index = (packet_in_window_index + 1) % WINDOW_SIZE + nak = ~self._await_can_msg(_validator, timeout=NAK_TIMEOUT) + + if nak == False: + print(f"WE LIT!!!!! PACKET {self.__transmission_address} recieved\n") + + elif nak == True: + print(f"PACKET DROPPED AT {self.__transmission_address}\n") + else: + print("TIMEOUT\n") + # Empirically, this tiny delay between messages seems to improve reliability. time.sleep(0.0005) From 1eb9a0b5329e9ab8356045a50f2363069962e97a Mon Sep 17 00:00:00 2001 From: shayana18 Date: Sat, 24 May 2025 19:17:16 -0700 Subject: [PATCH 5/6] ready to test --- bootloader.py | 96 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/bootloader.py b/bootloader.py index b1f8c3a..1dd4b7e 100644 --- a/bootloader.py +++ b/bootloader.py @@ -58,8 +58,6 @@ def __init__( self.timeout: int = timeout self.ui_callback: Callable = ui_callback self.dropped_packets = set() - self.__transmission_address = self.board.boot_id_range_start - def goto_bootloader(self) -> bool: """ Pushes all boards to bootloader mode. @@ -194,48 +192,84 @@ def program(self) -> None: # if we do want to move back to the closest interval of 4 then we need to figure out how to reflash adddresses that were already flashed (ie if its address 247 and the closest interval of 4 is 244) then we will attempt to reflash 244-246 even though they have already been flashed. Now with the # stm32s to write to flash memory we need to first erase it. Now if that is the case we need to figure out how to erase as the stm32 can only erase sectors at a time which is 16kb.... I am unsure on what happens if we try to flash memory that has not been erased. If it retains its originally value that that would be best and we can jsut do redundant flashing until we # get to the address that actually needs to be reflashed. - + + self.__transmission_address = self.ih.minaddr() + self.__transmission_id = self.board.boot_id_range_start | APP_START_PROGRAM_ID + self.__index = 0 + def _validator(msg: can.Message): # Ignore all known status messages print(f"Can ID that come through {msg.arbitration_id}\n") if msg.arbitration_id == (self.board.boot_id_range_start | NAK_ID): - self.__transmission_address = int.from_bytes(msg.data, "little") + dropped_packet_address = int.from_bytes(msg.data, "little") + self.__transmission_address = (dropped_packet_address // 8) * 8 + self.__index = dropped_packet_address % 8 + self.__transmission_id = self.board.boot_id_range_start | APP_START_PROGRAM_ID return False else: return True - for i, address in enumerate( - range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) - ): - self.__transmission_address = address #use an internal pointer + while self.__transmission_address < self.ih.minaddr() + self.size_bytes(): - if self.ui_callback and i % 128 == 0: - self.ui_callback("Programming data", self.size_bytes(), i * 8) - data = [self.ih[address + i] for i in range(0, 8)] + if self.ui_callback and self.__index % 128 == 0: + self.ui_callback("Programming data", self.size_bytes(), self.__index * 8) + self.__index += 1 + + data = [self.ih[self.__transmission_address + i] for i in range(0, 8)] success = False - while not success: - try: - self.bus.send( - can.Message( - arbitration_id=address, - data=data, - is_extended_id=True, + if(self.__transmission_id <= (self.board.boot_id_range_start | FINAL_PROGRAM_ID)): + while not success: + try: + self.bus.send( + can.Message( + arbitration_id=self.__transmission_id, + data=data, + is_extended_id=True, + ) ) - ) - success = True - except can.interfaces.vector.exceptions.VectorOperationError: - pass + success = True + except can.interfaces.vector.exceptions.VectorOperationError: + pass + + nak = ~self._await_can_msg(_validator, timeout=NAK_TIMEOUT) + + if nak == False: + print(f"WE LIT!!!!! PACKET {self.__transmission_address} recieved\n") + self.__transmission_address += 8 + elif nak == True: + print(f"PACKET DROPPED, Re-transmission starting at address {self.__transmission_address}\n") + print(f"PACKET DROPPED, Re-transmission starting at index {self.__index}\n") + else: + print("TIMEOUT\n") + + + # for i, address in enumerate( + # range(self.ih.minaddr(), self.ih.minaddr() + self.size_bytes(), 8) + # ): + # self.__transmission_address = address #use an internal pointer + + # if self.ui_callback and i % 128 == 0: + # self.ui_callback("Programming data", self.size_bytes(), i * 8) + # data = [self.ih[address + i] for i in range(0, 8)] + + # success = False + # if(self.__transmission_id <= (self.board.boot_id_range_start | FINAL_PROGRAM_ID)): + # while not success: + # try: + # self.bus.send( + # can.Message( + # arbitration_id=self.__transmission_id, + # data=data, + # is_extended_id=True, + # ) + # ) + # success = True + # except can.interfaces.vector.exceptions.VectorOperationError: + # pass + # else: + # print(f"RAN OUT OF BOARD IDS, current can ID {self.__transmission_id}") - nak = ~self._await_can_msg(_validator, timeout=NAK_TIMEOUT) - - if nak == False: - print(f"WE LIT!!!!! PACKET {self.__transmission_address} recieved\n") - - elif nak == True: - print(f"PACKET DROPPED AT {self.__transmission_address}\n") - else: - print("TIMEOUT\n") # Empirically, this tiny delay between messages seems to improve reliability. time.sleep(0.0005) From 31588c3c3476a16a2088b615c0751532ab18e4e8 Mon Sep 17 00:00:00 2001 From: shayana18 Date: Sat, 24 May 2025 19:36:21 -0700 Subject: [PATCH 6/6] clean up ... a bit --- bootloader.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bootloader.py b/bootloader.py index 2ca7b62..098a47c 100644 --- a/bootloader.py +++ b/bootloader.py @@ -186,12 +186,6 @@ def program(self) -> None: by computing a checksum. """ - # updated TCP inspired can bootloading: sender will send packet with can id's representing their memory address. The reciever will expect a can ID, of the sender can ID and reciever can ID match all is good, if there is a miss match the board will transmit the excepted can ID back. - # if the expected Can ID is a multiple of 4 it will directly be sent back to the user to begin retransmission at that address, if it is not an interval of 4 then retransmision is restarted at the closests (smaller) interval of 4. Note that a nuiassnace that we have to figure out is that - # if we do want to move back to the closest interval of 4 then we need to figure out how to reflash adddresses that were already flashed (ie if its address 247 and the closest interval of 4 is 244) then we will attempt to reflash 244-246 even though they have already been flashed. Now with the - # stm32s to write to flash memory we need to first erase it. Now if that is the case we need to figure out how to erase as the stm32 can only erase sectors at a time which is 16kb.... I am unsure on what happens if we try to flash memory that has not been erased. If it retains its originally value that that would be best and we can jsut do redundant flashing until we - # get to the address that actually needs to be reflashed. - self.__transmission_address = self.ih.minaddr() self.__transmission_id = self.board.boot_id_range_start | APP_START_PROGRAM_ID self.__index = 0