Index: scripts/update_package_script/update_package.py =================================================================== diff -u -r2c4faeb6256124837d794dc6c8df27a448ca3f13 -rbfc43b17282fbce6b3e56639f580d11665177bfb --- scripts/update_package_script/update_package.py (.../update_package.py) (revision 2c4faeb6256124837d794dc6c8df27a448ca3f13) +++ scripts/update_package_script/update_package.py (.../update_package.py) (revision bfc43b17282fbce6b3e56639f580d11665177bfb) @@ -18,6 +18,8 @@ _BINARY_FILE_SIZE = 'file_size' _WRITTEN_BYTE_COUNT = 'byte_count' _WRITE_COUNTER = 'write_counter' + _CUR_UPDATE_ELAPSED_TIME_S = 'elapsed_time_s' + _BINARY_LEN_BYTES = 'binary_len_bytes' def __init__(self): """ @@ -40,6 +42,8 @@ self._sw_update_status[self._BINARY_FILE_SIZE] = 0 self._sw_update_status[self._WRITTEN_BYTE_COUNT] = 0 self._sw_update_status[self._WRITE_COUNTER] = 0 + self._sw_update_status[self._CUR_UPDATE_ELAPSED_TIME_S] = 0 + self._sw_update_status[self._BINARY_LEN_BYTES] = 0 self._utilities.clear_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) self._utilities.clear_msg_ack_nack_status(self._utilities.UPDATE_MSG_ACK_STATUS_KEY_NAME) @@ -59,14 +63,14 @@ # TODO how to read from a manifest file. Right now it is passed directly # TODO if stack to update and stack target are not provided, then just read through the manifest files if stack_to_update is not None and destination is not None: - print("I", stack_to_update, int(stack_to_update)) stack_to_update = stack_to_update.upper() destination = destination.upper() self._sw_update_status[self._SW_UPDATE_STACK] = UpdateStacks(int(stack_to_update)).value self._sw_update_status[self._SW_UPDATE_DEST] = UpdateStacksDestinations(int(destination)).value #if stack_to_update in UpdateStacks.__members__: self._sw_update_status[self._SW_UPDATE_STACK] = UpdateStacks(stack_to_update).value #if destination in UpdateStacksDestinations.__members__: self._sw_update_status[self._SW_UPDATE_DEST] = UpdateStacksDestinations(destination).value + self._sw_update_status[self._CUR_UPDATE_ELAPSED_TIME_S] = time.time() # TODo manifest #self._sw_update_status[self._SW_UPDATE_STACK] = stack_to_update @@ -76,7 +80,7 @@ send_ack_status = self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) # If the communication has not started, send the command start for update if send_ack_status == CanCommStatus.CAN_COMM_NOT_STARTED.value: - self._utilities.send_command_msg(SWUpdateCommands.SW_UPDATE_START.value, + self._utilities.send_command_msg(SWUpdateCommands.UPDATE_CMD_START.value, self._sw_update_status[self._SW_UPDATE_STACK], self._sw_update_status[self._SW_UPDATE_DEST]) send_ack_status = self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) @@ -85,22 +89,24 @@ return status - def _update_progress_status(self, binary_len: int): + def _update_progress_status(self, clear_print: bool = False): """ Privately accessible method to print the status of software update. - @param binary_len: The length of the line read from a binary file (e.g. 256 bytes) + @param clear_print: boolean flag to indicate whether to send an empty print to break the continuous progress print line @return none """ progress_bar_scale = 100 # TODo this was 10. This should automatically scale + binary_len = self._sw_update_status[self._BINARY_LEN_BYTES] write_counter = self._sw_update_status[self._WRITE_COUNTER] binary_file_size_bytes = self._sw_update_status[self._BINARY_FILE_SIZE] target_stack = self._sw_update_status[self._SW_UPDATE_STACK] target_stack = UpdateStacksDestinations(target_stack).name destination = self._sw_update_status[self._SW_UPDATE_DEST] destination = UpdateStacks(destination).name bytes_written = self._sw_update_status[self._WRITTEN_BYTE_COUNT] + elapsed_time = time.time() - self._sw_update_status[self._CUR_UPDATE_ELAPSED_TIME_S] # Get number of payloads needed to update the binary but since this is for display only, it is scaled down 10 times num_of_payloads_needed = math.ceil(binary_file_size_bytes / (self._SW_UPDATE_PAYLOAD_BYTES * progress_bar_scale)) # Update the latest number of bytes that were successfully sent to the bootloader @@ -116,11 +122,11 @@ text = '#' * write_counter + ' ' * (num_of_payloads_needed - write_counter) # Print the update, end='\r' so the carriage return is returned to the beginning of the current line # add flush=True so the data is not buffered and is immediately printed - print("Updating: {} {} {} {:.1f}%".format(destination, target_stack, text, percent), end='\r', flush=True) + print("Updating: {} {} {} {:.1f}% Elapsed Time: {:.1f} s".format(destination, target_stack, text, percent, elapsed_time), end='\r', flush=True) self._sw_update_status[self._WRITTEN_BYTE_COUNT] = bytes_written self._sw_update_status[self._WRITE_COUNTER] = write_counter # Once all the bytes of a binary are written, print an empty print to bread from the progress print that was overwriting - if bytes_written >= binary_file_size_bytes: print() + if bytes_written >= binary_file_size_bytes and clear_print: print() def _process_binary_file(self, file_path: str): """ @@ -134,34 +140,59 @@ # Open the file as read the binary f = open(file_path, 'rb') while True: - line = None update_ack_status = self._utilities.get_msg_ack_nack_status(self._utilities.UPDATE_MSG_ACK_STATUS_KEY_NAME) # Read through the file, once ack status says the CAN bus is ready read another batch of bytes if update_ack_status == CanCommStatus.CAN_COMM_READY.value: # Read the next batch of bytes in the provided number of bytes line = f.read(self._SW_UPDATE_PAYLOAD_BYTES) target = self._sw_update_status[self._SW_UPDATE_STACK] + self._sw_update_status[self._BINARY_LEN_BYTES] = len(line) if line != b'': # If the read line is not b'', meaning that it was not empty, send the data to the bootloader self._utilities.send_software_update_msg(target, line, len(line)) - self._update_progress_status(len(line)) + self._update_progress_status() if line == b'': - # Read line was b'' meaning the binary file was read completely, send the verification command to the bootloader - self._utilities.send_command_msg(SWUpdateCommands.SW_UPDATE_VERIFY.value, - self._sw_update_status[self._SW_UPDATE_STACK], - self._sw_update_status[self._SW_UPDATE_DEST]) + # No more binary bytes left exit break elif update_ack_status == CanCommStatus.CAN_COMM_TIME_OUT.value: print() print("Timeout") # TODO send again? break - if line == b'': print("Leave file 2"); break # TODO remove this line # Close the binary file f.close() + def _verify_stack_update(self): + """ + Privately accessible method to process the stack has been updated. + + @return none + """ + send_ack_status = self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) + # If the CAN bus is ready for another communication, and if the destination was FPGA send the self configure command first + if self._sw_update_status[self._SW_UPDATE_DEST] == UpdateStacksDestinations.TARGET_FPGA.value and \ + send_ack_status == CanCommStatus.CAN_COMM_READY.value: + self._utilities.send_command_msg(SWUpdateCommands.UPDATE_CMD_CONFIG_FPGA.value, + self._sw_update_status[self._SW_UPDATE_STACK], + self._sw_update_status[self._SW_UPDATE_DEST]) + # Update the progress to show the verification step + self._update_progress_status(True) + + send_ack_status = self._utilities.get_msg_ack_nack_status(self._utilities.SEND_MSG_ACK_STATUS_KEY_NAME) + # If the communication has not started, send the command start for update + if send_ack_status == CanCommStatus.CAN_COMM_READY.value: + self._utilities.send_command_msg(SWUpdateCommands.UPDATE_CMD_VERIFY.value, + self._sw_update_status[self._SW_UPDATE_STACK], + self._sw_update_status[self._SW_UPDATE_DEST]) + def _handle_broadcast_message_thread(self, start_thread: bool): - # TODO add doxygen + """ + Privately accessible method to broadcast the send the update is available broadcast message at the defined interval. + + @param start_thread: The boolean flag to indicate whether to start the broadcast thread or to stop it. + + @return none + """ if start_thread: self._thread_event = threading.Event() self._thread = threading.Thread(target=self._utilities.send_update_available_broadcast_message, @@ -185,7 +216,6 @@ """ # Reset firmware - # Broadcast I have an update # Wait for the bootloader to come up # Start updating @@ -198,6 +228,8 @@ if self._prepare_for_sw_update(stack_to_update, stack_target, path): self._process_binary_file(path) + self._verify_stack_update() + # TODO reset command # Done with update binary files, stop sending the broadcast message #self._handle_broadcast_message_thread(start_thread=False)