def flash_block( client: Client, filename: str, block: constants.PreparedBlockData, vin: str, flash_info: constants.FlashInfo, tuner_tag: str = "", callback=None, ): block_number = block.block_number data = block.block_encrypted_bytes block_identifier = flash_info.block_identifiers[block_number] logger.info(vin + ": Flashing block: " + str(block_number) + " from file " + filename) detailedLogger.info("Beginning block flashing process for block " + str(block_number) + " : " + block.block_name + " - with file named " + filename + " ...") if callback: callback( flasher_step="FLASHING", flasher_status="Erasing block " + str(block_number), flasher_progress=0, ) # Erase Flash if block.should_erase: detailedLogger.info("Erasing block " + str(block_number) + ", routine 0xFF00...") client.start_routine(Routine.EraseMemory, data=bytes([0x1, block_identifier])) if callback: callback( flasher_step="FLASHING", flasher_status="Requesting Download for block " + str(block_number), flasher_progress=0, ) detailedLogger.info("Requesting download for block " + str(block_number) + " of length " + str(flash_info.block_lengths[block_number]) + " with block identifier: " + str(block_identifier)) # Request Download dfi = udsoncan.DataFormatIdentifier(compression=block.compression_type, encryption=block.encryption_type) memloc = udsoncan.MemoryLocation( block_identifier, flash_info.block_lengths[block_number], address_format=8, memorysize_format=32, ) client.request_download(memloc, dfi=dfi) if callback: callback( flasher_step="FLASHING", flasher_status="Transferring data... " + str(len(data)), flasher_progress=0, ) detailedLogger.info("Transferring data... " + str(len(data)) + " bytes to write") # Transfer Data counter = 1 for block_base_address in range( 0, len(data), flash_info.block_transfer_sizes[block_number]): if callback: progress = (100 * counter * flash_info.block_transfer_sizes[block_number] / len(data)) callback( flasher_step="FLASHING", flasher_status="Transferring data... ", flasher_progress=str(progress), ) block_end = min( len(data), block_base_address + flash_info.block_transfer_sizes[block_number], ) client.transfer_data(counter, data[block_base_address:block_end]) counter = next_counter(counter) if callback: callback( flasher_step="FLASHING", flasher_status="Exiting transfer... ", flasher_progress=100, ) detailedLogger.info("Exiting transfer...") # Exit Transfer client.request_transfer_exit() if (len(tuner_tag) > 0) and (block_number > 1): detailedLogger.info("Sending tuner ASW magic number...") # Send Magic # In the case of a tuned CBOOT, send tune-specific magic bytes after this 3E to force-overwrite the CAL validity area. def tuner_payload(payload, tune_block_number=block_number): return payload + bytes(tuner_tag, "ascii") + bytes( [tune_block_number]) with client.payload_override(tuner_payload): client.tester_present() else: client.tester_present() if callback: callback( flasher_step="FLASHING", flasher_status="Checksumming block... ", flasher_progress=100, ) detailedLogger.info("Checksumming block " + str(block_number) + " , routine 0x0202...") # Checksum checksum_data = bytearray([0x01, block_identifier, 0, 0x4]) checksum_data.extend(block.uds_checksum) client.start_routine(0x0202, data=bytes(checksum_data)) if callback: callback( flasher_step="FLASHING", flasher_status="Success flashing block... ", flasher_progress=100, ) logger.info(vin + ": Success flashing block: " + str(block_number) + " with " + filename) detailedLogger.info("Successfully flashed " + filename + " to block " + str(block_number))
def patch_block( client: Client, filename: str, block: constants.PreparedBlockData, vin: str, flash_info: constants.FlashInfo, callback=None, ): block_number = block.block_number block_number = block_number - 5 data = block.block_encrypted_bytes detailedLogger.info( "Erasing next block for PATCH process - erasing block " + str(block_number + 1) + " to patch " + str(block_number) + " routine 0xFF00...") # Erase Flash # Hardcoded to erase block 5 (CAL) prior to patch. This means we must ALWAYS flash CAL after patching. client.start_routine(Routine.EraseMemory, data=bytes([0x1, 5])) logger.info(vin + ": PATCHING block: " + str(block_number) + " with " + filename) detailedLogger.info("Requesting download to PATCH block " + str(block_number) + " of length " + str(flash_info.block_lengths[block_number]) + " using file " + filename + " ...") # Request Download dfi = udsoncan.DataFormatIdentifier(compression=0x0, encryption=0xA) memloc = udsoncan.MemoryLocation(block_number, flash_info.block_lengths[block_number], memorysize_format=32) client.request_download(memloc, dfi=dfi) detailedLogger.info("Transferring PATCH data... " + str(len(data)) + " bytes to write") # Transfer Data counter = 1 transfer_address = 0 while transfer_address < len(data): transfer_size = flash_info.patch_info.block_transfer_sizes_patch( block_number, transfer_address) block_end = min(len(data), transfer_address + transfer_size) transfer_data = data[transfer_address:block_end] if callback: progress = transfer_address * 100 / len(data) callback( flasher_step="PATCHING", flasher_status="Patching data... ", flasher_progress=str(progress), ) success = False while not success: try: time.sleep(0.025) client.transfer_data(counter, transfer_data) success = True counter = next_counter(counter) except exceptions.NegativeResponseException: success = False counter = next_counter(counter) transfer_address += transfer_size detailedLogger.info("Exiting PATCH transfer...") # Exit Transfer client.request_transfer_exit() detailedLogger.info("PATCH successful.") logger.info(vin + ": PATCHED block: " + str(block_number) + " with " + filename)