copro.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import logging
  2. import json
  3. from io import BytesIO
  4. import tarfile
  5. import xml.etree.ElementTree as ET
  6. import posixpath
  7. import os
  8. from flipper.utils import file_sha256, timestamp
  9. from flipper.assets.coprobin import CoproBinary, get_stack_type
  10. CUBE_COPRO_PATH = "Projects/STM32WB_Copro_Wireless_Binaries"
  11. MANIFEST_TEMPLATE = {
  12. "manifest": {"version": 0, "timestamp": 0},
  13. "copro": {
  14. "fus": {"version": {"major": 1, "minor": 2, "sub": 0}, "files": []},
  15. "radio": {
  16. "version": {},
  17. "files": [],
  18. },
  19. },
  20. }
  21. class Copro:
  22. COPRO_TAR_DIR = "core2_firmware"
  23. def __init__(self, mcu):
  24. self.mcu = mcu
  25. self.version = None
  26. self.cube_dir = None
  27. self.mcu_copro = None
  28. self.logger = logging.getLogger(self.__class__.__name__)
  29. def loadCubeInfo(self, cube_dir, reference_cube_version):
  30. if not os.path.isdir(cube_dir):
  31. raise Exception(f'"{cube_dir}" doesn\'t exists')
  32. self.cube_dir = cube_dir
  33. self.mcu_copro = os.path.join(self.cube_dir, CUBE_COPRO_PATH, self.mcu)
  34. if not os.path.isdir(self.mcu_copro):
  35. raise Exception(f'"{self.mcu_copro}" doesn\'t exists')
  36. cube_manifest_file = os.path.join(self.cube_dir, "package.xml")
  37. cube_manifest = ET.parse(cube_manifest_file)
  38. cube_package = cube_manifest.find("PackDescription")
  39. if not cube_package:
  40. raise Exception("Unknown Cube manifest format")
  41. cube_version = cube_package.get("Patch") or cube_package.get("Release")
  42. if not cube_version or not cube_version.startswith("FW.WB"):
  43. raise Exception("Incorrect Cube package or version info")
  44. cube_version = cube_version.replace("FW.WB.", "", 1)
  45. if cube_version != reference_cube_version:
  46. raise Exception("Unsupported cube version")
  47. self.version = cube_version
  48. def _getFileName(self, name):
  49. return posixpath.join(self.COPRO_TAR_DIR, name)
  50. def addFile(self, array, filename, **kwargs):
  51. source_file = os.path.join(self.mcu_copro, filename)
  52. self.output_tar.add(source_file, arcname=self._getFileName(filename))
  53. array.append({"name": filename, "sha256": file_sha256(source_file), **kwargs})
  54. def bundle(self, output_file, stack_file_name, stack_type, stack_addr=None):
  55. self.output_tar = tarfile.open(output_file, "w:gz", format=tarfile.USTAR_FORMAT)
  56. fw_directory = tarfile.TarInfo(self.COPRO_TAR_DIR)
  57. fw_directory.type = tarfile.DIRTYPE
  58. self.output_tar.addfile(fw_directory)
  59. stack_file = os.path.join(self.mcu_copro, stack_file_name)
  60. # Form Manifest
  61. manifest = dict(MANIFEST_TEMPLATE)
  62. manifest["manifest"]["timestamp"] = timestamp()
  63. copro_bin = CoproBinary(stack_file)
  64. self.logger.info(f"Bundling {copro_bin.img_sig.get_version()}")
  65. stack_type_code = get_stack_type(stack_type)
  66. manifest["copro"]["radio"]["version"].update(
  67. {
  68. "type": stack_type_code,
  69. "major": copro_bin.img_sig.version_major,
  70. "minor": copro_bin.img_sig.version_minor,
  71. "sub": copro_bin.img_sig.version_sub,
  72. "branch": copro_bin.img_sig.version_branch,
  73. "release": copro_bin.img_sig.version_build,
  74. }
  75. )
  76. if not stack_addr:
  77. stack_addr = copro_bin.get_flash_load_addr()
  78. self.logger.info(f"Using guessed flash address 0x{stack_addr:x}")
  79. # Old FUS Update
  80. self.addFile(
  81. manifest["copro"]["fus"]["files"],
  82. "stm32wb5x_FUS_fw_for_fus_0_5_3.bin",
  83. condition="==0.5.3",
  84. address="0x080EC000",
  85. )
  86. # New FUS Update
  87. self.addFile(
  88. manifest["copro"]["fus"]["files"],
  89. "stm32wb5x_FUS_fw.bin",
  90. condition=">0.5.3",
  91. address="0x080EC000",
  92. )
  93. # BLE Full Stack
  94. self.addFile(
  95. manifest["copro"]["radio"]["files"],
  96. stack_file_name,
  97. address=f"0x{stack_addr:X}",
  98. )
  99. # Save manifest
  100. manifest_data = json.dumps(manifest, indent=4).encode("utf-8")
  101. info = tarfile.TarInfo(self._getFileName("Manifest.json"))
  102. info.size = len(manifest_data)
  103. self.output_tar.addfile(info, BytesIO(manifest_data))
  104. self.output_tar.close()