diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f3d9b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +images/ +out/ diff --git a/main.py b/main.py new file mode 100644 index 0000000..9e6466d --- /dev/null +++ b/main.py @@ -0,0 +1,212 @@ +# This is a sample Python script. +import enum +# Press Umschalt+F10 to execute it or replace it with your code. +# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings. + +import os +import struct +from argparse import ArgumentParser +from io import BytesIO +from typing import BinaryIO +import hashlib +import json + +from pygccxml.declarations import unsigned_int_t + + +class AImage(object): + def parse(self): + pass + + def version(self): + pass + + def is_valid(self): + return False + + @staticmethod + def _check(data: bytes, target: dict): + is_valid = True + is_valid &= AImage._check_len(data, target['LEN']) + is_valid &= AImage._check_fingerprint(data, target['DIGEST']) + is_valid &= AImage._check_version(data, 0x1B430, bytearray.fromhex(target['VERSION'])) + + print("is_valid =", is_valid) + + return is_valid + + @staticmethod + def _check_len(data: bytes, target: int): + return len(data) == target + + @staticmethod + def _check_fingerprint(data: bytes, target: str): + h = hashlib.sha256() + h.update(data) + actual = h.digest() + print(actual) + return actual == target + + @staticmethod + def _check_version(data: bytes, offset : int, target: bytearray): + actual = data[offset:offset+len(target)] + print(actual) + return actual == target + + def get_waves(self): + pass + + def get_wave_tables(self): + pass + +class WaldorfMicroWave1V20(AImage): + pass + + +class WaldorfMicroWave1V25(AImage): + pass + +class WaldorfMicroWave2V00(AImage): + class ImagePart(enum.Enum): + Hi = 0 + Lo = 1 + + target = { + "LEN" : 131072, + "DIGEST" : b'\xe3G\n~\xfb\xd0P\xf4~\x8d\xf3\x12p9\x88X\x95e\xc2\xc5e\xdev\xe6\r\xaba\x8b\xadDY\x90', + "VERSION" : "322E3030300000004D6F6E204D617220372031323A30363A3132204D4554203139393400303230303934303337000000" + } + + wave_data_descr = [ + { + 'offset': 0xAA18, + 'len': 0x1B00 + }, + { + 'offset': 0xAA18, + 'len': 0x3000 + } + ] + + wave_tables_descr = [ + { + 'offset': 0x9A18, + 'len': 0x0E00 + }, + { + 'offset': 0x9A18, + 'len': 0x0600 + } + ] + + def __init__(self, filename_hi: str, filename_lo: str, out_dir="."): + self.out_dir = out_dir + data, data_hi, data_lo = self.combine(filename_hi, filename_lo) + + self._is_valid = self._check(data, self.target) + if self._is_valid: + self._save("combined_test_be.bin", data) + + wave_data = self.wave_extract(self.wave_data_descr, data_hi, data_lo) + self._save("wave_data.bin", wave_data) + + wave_table = self.wave_table_extract(self.wave_tables_descr, data_hi, data_lo) + self._json_save("wave_table.json", wave_table) + + + def _save(self, filename: str, data): + with open(os.path.join(self.out_dir, filename), 'wb') as fp: + fp.write(data) + + def _json_save(self, filename: str, data): + with open(os.path.join(self.out_dir, filename), 'wb') as fp: + json.dump(data, fp, indent=4) + + @staticmethod + def wave_extract(descr, data_hi, data_lo): + data = b'' + for des, rom_data in zip(descr, [data_hi, data_lo]): + offset = des['offset'] + length = des['len'] + data += rom_data[offset:offset+length] + return data + + @staticmethod + def wave_table_extract(descr, data_hi, data_lo): + + data = [] + table_count = 0 + pos = 0 + for des, rom_data in zip(descr, [data_hi, data_lo]): + offset = des['offset'] + length = des['len'] + + for addr in range(offset, offset + length, 2): + index = struct.unpack('>h', rom_data[addr:addr+2])[0] + if index > 0: + if pos == 0: + print(f"----------------------------") + print(f"- table #{table_count:03d}") + print(f"----------------------------") + table_count += 1 + entry = {"index": index, "pos": pos} + print(entry) + data.append(entry) + + if pos < 63: + pos += 1 + else: + pos = 0 + return data + + def is_valid(self): + return self._is_valid + + @staticmethod + def combine(filename_hi: str, filename_lo: str): + data_hi = b'' + data_lo = b'' + with open(filename_hi, "rb") as fp: + data_hi = fp.read() + with open(filename_lo, "rb") as fp: + data_lo = fp.read() + + data = b'' + for hi, lo in zip(data_hi, data_lo): + z = int.from_bytes([hi, lo], byteorder='big') + b = struct.pack('>H', z) + data += b + + return data, data_hi, data_lo + + + +class PpgEvu1v00(AImage): + pass + +class PpgEvu2v00(AImage): + pass + + +def detect(args): + os.makedirs(args.output_dir) + image = WaldorfMicroWave2V00(args.filepath, args.extra, args.output_dir) + pass + +def main(args): + image_type = detect(args) + + +if __name__ == '__main__': + parser = ArgumentParser() + parser.add_argument("filepath", help="Location of firmware binary image") + parser.add_argument("--extra", help="Location of firmware binary image") + parser.add_argument("--output_dir", help="Location of output data", default='out') + + args = parser.parse_args() + + main(args) + + + +# See PyCharm help at https://www.jetbrains.com/help/pycharm/