Index: scripts/update_package_script/update_package.py =================================================================== diff -u -rbfc43b17282fbce6b3e56639f580d11665177bfb -r4958f2a616031e26b9d0f662b4faca8b28832a53 --- scripts/update_package_script/update_package.py (.../update_package.py) (revision bfc43b17282fbce6b3e56639f580d11665177bfb) +++ scripts/update_package_script/update_package.py (.../update_package.py) (revision 4958f2a616031e26b9d0f662b4faca8b28832a53) @@ -3,6 +3,7 @@ import math import time import threading +import subprocess from scripts.update_package_script.utilities import Utilities, SWUpdateCommands, CanCommStatus, UpdateStacks, UpdateStacksDestinations class SoftwareUpdateScript: @@ -11,8 +12,8 @@ The class runs the firmware and FPGA updates """ - _SW_UPDATE_PAYLOAD_BYTES = 512 - _BROADCAST_MESSAGE_INTERVAL_S = 0.2 + _SW_UPDATE_PAYLOAD_BYTES = 512 #256 #512 + _BROADCAST_MESSAGE_INTERVAL_S = 0.1 _SW_UPDATE_STACK = 'stack_name' _SW_UPDATE_DEST = 'stack_target' _BINARY_FILE_SIZE = 'file_size' @@ -97,21 +98,23 @@ @return none """ - progress_bar_scale = 100 # TODo this was 10. This should automatically scale + progress_bar_scale = 10 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 + target_stack = UpdateStacks(target_stack).name destination = self._sw_update_status[self._SW_UPDATE_DEST] - destination = UpdateStacks(destination).name + destination = UpdateStacksDestinations(destination).name bytes_written = self._sw_update_status[self._WRITTEN_BYTE_COUNT] + # If the file size is greater than 1 MB, then set the scale to bigger than default so the progress fits in the screen + if binary_file_size_bytes >= 1000000: progress_bar_scale = 100 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 + # Get number of payloads needed to update the binary but since this is for display only, it is scaled down 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 bytes_written += binary_len - # If the accumulation of the bytes written is a division of the scale (10) then update the progress bar + # If the accumulation of the bytes written is a division of the scale (for display) then update the progress bar if bytes_written % (self._SW_UPDATE_PAYLOAD_BYTES * progress_bar_scale) == 0: write_counter += 1 # If the length of the bytes written is less than the default bytes to extract and write, it means we are the end of the # update of the binary file, then update the progress bar @@ -122,7 +125,7 @@ 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}% Elapsed Time: {:.1f} s".format(destination, target_stack, text, percent, elapsed_time), end='\r', flush=True) + print("Updating: {} {} {} {:.1f}% Elapsed Time: {:.1f} s".format(target_stack, destination, 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 @@ -185,6 +188,23 @@ self._sw_update_status[self._SW_UPDATE_STACK], self._sw_update_status[self._SW_UPDATE_DEST]) + @staticmethod + def _find_binary_files(packages_dir: str): + """ + Privately accessible static method to find the binary files in the provided folder + + @param packages_dir: The directory to check the binary files + + @return A list of the binary files + """ + cmd = ['find', packages_dir, '-type', 'f', '-name', '*.bin'] + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + # Convert the binary to ASCII and ignore the errors in case an unexpected character was in the text + cmd_response = stdout.decode('ascii', errors='ignore').splitlines() + + return cmd_response + def _handle_broadcast_message_thread(self, start_thread: bool): """ Privately accessible method to broadcast the send the update is available broadcast message at the defined interval. @@ -204,7 +224,7 @@ ######################## PUBLIC METHOD(S) ############################## - def update_software_packages(self, packages_dir: str, stack_to_update: str = None, stack_target: str = None): + def update_software_packages(self, packages_dir: str, stack_to_update: str = None, destination: str = None): """ Publicly accessible method to update the software packages (firmware and FPGA) @@ -219,17 +239,16 @@ # Wait for the bootloader to come up # Start updating - # TODO check if the update folder is empty then send the thread + list_of_binary_files = self._find_binary_files(packages_dir) + if len(list_of_binary_files) == 0: exit(0) # No binary files to process + #self._handle_broadcast_message_thread(start_thread=True) + for binary_file in list_of_binary_files: + # Make sure the file is opened a binary or hex + if not binary_file.endswith(".bin") and not binary_file.endswith(".hex"): continue + if self._prepare_for_sw_update(stack_to_update, destination, binary_file): + self._process_binary_file(binary_file) + self._verify_stack_update() # TODO skip if the timeout or another error - for file in os.listdir(packages_dir): - if not file.endswith(".bin") and not file.endswith(".hex"): continue - path = os.path.join(packages_dir, file) - - 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)