|
| 1 | +# Script for generating a firmware package |
| 2 | + |
| 3 | +import os |
| 4 | +import csv |
| 5 | +import json |
| 6 | +import zlib |
| 7 | +import shutil |
| 8 | + |
| 9 | +def convert_size(size_str): |
| 10 | + """Convert size string to bytes.""" |
| 11 | + if size_str.endswith("K"): |
| 12 | + return int(size_str[:-1]) * 1024 |
| 13 | + elif size_str.endswith("M"): |
| 14 | + return int(size_str[:-1]) * 1024 * 1024 |
| 15 | + elif size_str.endswith("G"): |
| 16 | + return int(size_str[:-1]) * 1024 * 1024 * 1024 |
| 17 | + else: |
| 18 | + return int(size_str) |
| 19 | + |
| 20 | +def read_partition_table(filename): |
| 21 | + partitions = [] |
| 22 | + with open(filename, "r") as f: |
| 23 | + data = f.read() |
| 24 | + lines = data.splitlines() |
| 25 | + lines = [line for line in lines if not line.strip().startswith("#")] |
| 26 | + reader = csv.reader(lines) |
| 27 | + for row in reader: |
| 28 | + partition = { |
| 29 | + "name": row[0], |
| 30 | + "type": row[1], |
| 31 | + "subtype": row[2], |
| 32 | + "offset": int(row[3], 16), |
| 33 | + "size": convert_size(row[4]), |
| 34 | + "flags": row[5], |
| 35 | + } |
| 36 | + partitions.append(partition) |
| 37 | + return partitions |
| 38 | + |
| 39 | +def find_partition(partitions, name): |
| 40 | + for partition in partitions: |
| 41 | + if partition["name"] == name: |
| 42 | + return partition |
| 43 | + return None |
| 44 | + |
| 45 | +def calculate_md5(filename): |
| 46 | + """Calculate MD5 checksum of a file.""" |
| 47 | + import hashlib |
| 48 | + hash_md5 = hashlib.md5() |
| 49 | + with open(filename, "rb") as f: |
| 50 | + for chunk in iter(lambda: f.read(4096), b""): |
| 51 | + hash_md5.update(chunk) |
| 52 | + return hash_md5.hexdigest() |
| 53 | + |
| 54 | +def get_size(filename): |
| 55 | + return os.path.getsize(filename) |
| 56 | + |
| 57 | +def compress(in_file, out_file): |
| 58 | + with open(in_file, "rb") as input_file: |
| 59 | + with open(out_file, "wb") as output_file: |
| 60 | + output_file.write(zlib.compress(input_file.read(), 9)) |
| 61 | + |
| 62 | +# Constants |
| 63 | +bootloader_offset = 0x2000 |
| 64 | +partition_table_offset = 0x8000 |
| 65 | +bootloader_path = "build/tanmatsu/bootloader/bootloader.bin" |
| 66 | +partition_table_csv_path = "partition_tables/16M.csv" |
| 67 | +partition_table_path = "build/tanmatsu/partition_table/partition-table.bin" |
| 68 | +firmware_path = "build/tanmatsu/tanmatsu-launcher.bin" |
| 69 | +ota_data_path = "build/tanmatsu/ota_data_initial.bin" |
| 70 | +locfd_path = "build/tanmatsu/locfd.bin" |
| 71 | + |
| 72 | +compress = False |
| 73 | + |
| 74 | +# Generate instructions |
| 75 | +partitions = read_partition_table(partition_table_csv_path) |
| 76 | +firmware_offset = find_partition(partitions, "ota_0")["offset"] |
| 77 | +ota_data_offset = find_partition(partitions, "otadata")["offset"] |
| 78 | +locfd_offset = find_partition(partitions, "locfd")["offset"] |
| 79 | + |
| 80 | + |
| 81 | +bootloader_hash = calculate_md5(bootloader_path) |
| 82 | +partitions_hash = calculate_md5(partition_table_path) |
| 83 | +ota_data_hash = calculate_md5(ota_data_path) |
| 84 | +firmware_hash = calculate_md5(firmware_path) |
| 85 | +locfd_hash = calculate_md5(locfd_path) |
| 86 | + |
| 87 | +bootloader_size = get_size(bootloader_path) |
| 88 | +partitions_size = get_size(partition_table_path) |
| 89 | +ota_data_size = get_size(ota_data_path) |
| 90 | +firmware_size = get_size(firmware_path) |
| 91 | +locfd_size = get_size(locfd_path) |
| 92 | + |
| 93 | +steps = [ |
| 94 | + {"file": "bootloader." + ("zz" if compress else "bin"), "offset": bootloader_offset, "hash": bootloader_hash, "size": bootloader_size, "compressed": compress, "optional": False}, |
| 95 | + {"file": "partitions." + ("zz" if compress else "bin"), "offset": partition_table_offset, "hash": partitions_hash, "size": partitions_size, "compressed": compress, "optional": False}, |
| 96 | + {"file": "ota_data." + ("zz" if compress else "bin"), "offset": ota_data_offset, "hash": ota_data_hash, "size": ota_data_size, "compressed": compress, "optional": False}, |
| 97 | + {"file": "firmware." + ("zz" if compress else "bin"), "offset": firmware_offset, "hash": firmware_hash, "size": firmware_size, "compressed": compress, "optional": False}, |
| 98 | + {"file": "locfd." + ("zz" if compress else "bin"), "offset": locfd_offset, "hash": locfd_hash, "size": locfd_size, "compressed": compress, "optional": True}, |
| 99 | +] |
| 100 | + |
| 101 | +instructions = { |
| 102 | + "information": { |
| 103 | + "name": "Tanmatsu launcher firmware", |
| 104 | + "version": "tbd" |
| 105 | + }, |
| 106 | + "steps": steps |
| 107 | +} |
| 108 | + |
| 109 | +try: |
| 110 | + os.mkdir("dist") |
| 111 | +except: |
| 112 | + pass |
| 113 | + |
| 114 | +# Save instructions to JSON file |
| 115 | +output_file = "dist/instructions.trf" |
| 116 | +with open(output_file, "w") as f: |
| 117 | + json.dump(instructions, f) |
| 118 | + |
| 119 | +if compress: |
| 120 | + # Compress firmware parts |
| 121 | + compress(bootloader_path, "dist/bootloader.zz") |
| 122 | + compress(partition_table_path, "dist/partitions.zz") |
| 123 | + compress(firmware_path, "dist/firmware.zz") |
| 124 | + compress(ota_data_path, "dist/ota_data.zz") |
| 125 | + compress(locfd_path, "dist/locfd.zz") |
| 126 | +else: |
| 127 | + shutil.copyfile(bootloader_path, "dist/bootloader.bin") |
| 128 | + shutil.copyfile(partition_table_path, "dist/partitions.bin") |
| 129 | + shutil.copyfile(firmware_path, "dist/firmware.bin") |
| 130 | + shutil.copyfile(ota_data_path, "dist/ota_data.bin") |
| 131 | + shutil.copyfile(locfd_path, "dist/locfd.bin") |
0 commit comments