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 *
  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(f"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(f"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(f"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()