Index: scripts/update_package_script/update_package.py =================================================================== diff -u -r167604cac199c133488d55eb0163e88eadd0e123 -r37ed1a7ad66212bf70875ea723fdae6576405ce8 --- scripts/update_package_script/update_package.py (.../update_package.py) (revision 167604cac199c133488d55eb0163e88eadd0e123) +++ scripts/update_package_script/update_package.py (.../update_package.py) (revision 37ed1a7ad66212bf70875ea723fdae6576405ce8) @@ -12,7 +12,7 @@ The class runs the firmware and FPGA updates """ - _SW_UPDATE_PAYLOAD_BYTES = 512 #256 #512 + _SW_UPDATE_PAYLOAD_BYTES = 512 #256 _BROADCAST_MESSAGE_INTERVAL_S = 0.1 _SW_UPDATE_STACK = 'stack_name' _SW_UPDATE_DEST = 'stack_target' @@ -22,6 +22,21 @@ _CUR_UPDATE_ELAPSED_TIME_S = 'elapsed_time_s' _BINARY_LEN_BYTES = 'binary_len_bytes' + _MCS_DATA_LINE_LEN = 43 + _MCS_START_CODE_DEC = ':' + _MCS_NUM_OF_BYTES_DEC = '10' + _MCS_NUM_OF_BYTES_PER_LINE = 16 + _MCS_DATA_DATA_TYPE_DEC = '00' + _MCS_LINE_CRC_LEN = 2 + _MCS_START_CODE_START_INDEX = 0 + _MCS_START_CODE_END_INDEX = 1 + _MCS_NUM_OF_BYTES_START_INDEX = 1 + _MCS_NUM_OF_BYTES_END_INDEX = 3 + _MCS_DATA_TYPE_START_INDEX = 7 + _MCS_DATA_TYPE_END_INDEX = 9 + _MCS_UPDATE_DATA_START_INDEX = 9 + + def __init__(self): """ SoftwareUpdateScript class constructor @@ -79,6 +94,19 @@ #self._sw_update_status[self._SW_UPDATE_STACK] = stack_to_update #self._sw_update_status[self._SW_UPDATE_TARGET] = stack_target self._sw_update_status[self._BINARY_FILE_SIZE] = os.path.getsize(file_path) + if file_path.endswith(".mcs"): + num_of_lines_with_data = 0 + # Command: grep -c ":10" Leahi_103488_ctlbrd_hyd_L018_update.mcs + # Look for the lines with :10 at the beginning of them + cmd = ['grep', '-c', '^' + self._MCS_START_CODE_DEC + self._MCS_NUM_OF_BYTES_DEC, file_path] + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = process.communicate() + cmd_response = stdout.decode('ascii', errors='ignore').splitlines() + # Get the number of lines with the character and multiply it by 16 bytes to get the number of the bytes that + # have to be written. This is essential for the progress status. Otherwise, the .mcs file has more data than + # the amount of data that is going to be written to the FPGA. + if len(cmd_response) > 0: num_of_lines_with_data = int(cmd_response[0]) + self._sw_update_status[self._BINARY_FILE_SIZE] = num_of_lines_with_data * self._MCS_NUM_OF_BYTES_PER_LINE 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 @@ -100,6 +128,7 @@ @return none """ + if clear_print: return # If clear print, return progress_bar_scale = 10 binary_len = self._sw_update_status[self._BINARY_LEN_BYTES] write_counter = self._sw_update_status[self._WRITE_COUNTER] @@ -110,14 +139,14 @@ 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 + if binary_file_size_bytes >= 1000000: progress_bar_scale = 50 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 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 (for display) then update the progress bar - if bytes_written % (self._SW_UPDATE_PAYLOAD_BYTES * progress_bar_scale) == 0: write_counter += 1 + 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 if binary_len < self._SW_UPDATE_PAYLOAD_BYTES: write_counter += 1 @@ -131,17 +160,16 @@ 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 and clear_print: print() + if bytes_written >= binary_file_size_bytes: print() - def _process_binary_file(self, file_path: str): + def _process_binary_update_file(self, file_path: str): """ Privately accessible method to process a passed binary file. @param file_path: The address of the binary file passed to the method @return none """ - # TODO add a timeout (e.g. 10 minutes that is very long) to make sure we are not stuck # Open the file as read the binary f = open(file_path, 'rb') while True: @@ -156,17 +184,65 @@ # 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() - if line == b'': - # No more binary bytes left exit - break + if line == b'': break # No more binary bytes left exit elif update_ack_status == CanCommStatus.CAN_COMM_TIME_OUT.value: print() print("Timeout") # TODO send again? break - # Close the binary file f.close() + def _process_mcs_update_file(self, file_path: str): + """ + Privately accessible method to process a passed Memory Configuration File (MCS) file. + + @param file_path: The address of the mcs file passed to the method + + @return none + """ + f = open(file_path, 'r') + payload_bytes = bytes() + for line in f: + line = line.strip() + # Read the line: e.g. :10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 -> :[Length][Address][Record Type][Data][Checksum] + # 1. ":" is the start of the line + # 2. length are the next 2 hex characters (e.g. 10 means 16 bytes of data) + # 3. address is the next 4 hex characters. It is not used now. + # 4. record type is the next 2 hex characters. 00 data record, 01 end of file, 04 extended linear address + # 5. data is the next defined bytes in item 2. + # 6. checksum is the last 2 hex characters. It is not used now. + # The lines below checks the read line to make sure it is a data line + if len(line) != self._MCS_DATA_LINE_LEN: continue + start_code = line[self._MCS_START_CODE_START_INDEX:self._MCS_START_CODE_END_INDEX] + if self._MCS_START_CODE_DEC not in start_code: continue + num_of_bytes = line[self._MCS_NUM_OF_BYTES_START_INDEX:self._MCS_NUM_OF_BYTES_END_INDEX] + if self._MCS_NUM_OF_BYTES_DEC != num_of_bytes: continue + data_type = line[self._MCS_DATA_TYPE_START_INDEX:self._MCS_DATA_TYPE_END_INDEX] + if self._MCS_DATA_DATA_TYPE_DEC != data_type: continue + update_data = line[self._MCS_UPDATE_DATA_START_INDEX:len(line) - self._MCS_LINE_CRC_LEN] + + for b in range(0, len(update_data)): + # Loop through the list of the data extracted data every two characters are concatenated to become one byte of data + # For example: 00000000300020010000001430014004 -> 00 00 00 00 30 00 20 01 00 00 00 14 30 01 40 04 + # So if the index of the value is odd, the value and the value of the previous index are combined and converted to integer + # The concatenated integer is the packed into a byte + if b % 2 == 0: continue + conc_bytes = update_data[b - 1] + update_data[b] + conc_int = int(conc_bytes, 16) + payload_bytes += self._utilities.convert_data_to_bytes('