2021-09-13 09:52:50 +00:00
|
|
|
import json
|
2023-05-08 21:30:33 +00:00
|
|
|
import logging
|
2022-10-18 12:13:28 +00:00
|
|
|
import os
|
2023-05-08 21:30:33 +00:00
|
|
|
import posixpath
|
|
|
|
import tarfile
|
|
|
|
from io import BytesIO
|
2022-10-12 16:12:05 +00:00
|
|
|
|
2022-04-27 15:53:48 +00:00
|
|
|
from flipper.assets.coprobin import CoproBinary, get_stack_type
|
2023-05-08 21:30:33 +00:00
|
|
|
from flipper.utils import file_sha256, timestamp
|
2022-04-27 15:53:48 +00:00
|
|
|
|
2023-05-08 21:30:33 +00:00
|
|
|
CUBE_COPRO_PATH = "firmware"
|
2021-09-13 09:52:50 +00:00
|
|
|
|
|
|
|
MANIFEST_TEMPLATE = {
|
|
|
|
"manifest": {"version": 0, "timestamp": 0},
|
|
|
|
"copro": {
|
|
|
|
"fus": {"version": {"major": 1, "minor": 2, "sub": 0}, "files": []},
|
|
|
|
"radio": {
|
2022-04-27 15:53:48 +00:00
|
|
|
"version": {},
|
2021-09-13 09:52:50 +00:00
|
|
|
"files": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Copro:
|
2022-10-18 12:13:28 +00:00
|
|
|
COPRO_TAR_DIR = "core2_firmware"
|
|
|
|
|
2023-05-08 21:30:33 +00:00
|
|
|
def __init__(self):
|
2021-09-13 09:52:50 +00:00
|
|
|
self.version = None
|
|
|
|
self.cube_dir = None
|
|
|
|
self.mcu_copro = None
|
|
|
|
self.logger = logging.getLogger(self.__class__.__name__)
|
|
|
|
|
2023-04-24 07:19:36 +00:00
|
|
|
def loadCubeInfo(self, cube_dir, reference_cube_version):
|
2021-09-13 09:52:50 +00:00
|
|
|
if not os.path.isdir(cube_dir):
|
|
|
|
raise Exception(f'"{cube_dir}" doesn\'t exists')
|
|
|
|
self.cube_dir = cube_dir
|
2023-05-08 21:30:33 +00:00
|
|
|
self.mcu_copro = os.path.join(self.cube_dir, CUBE_COPRO_PATH)
|
2021-09-13 09:52:50 +00:00
|
|
|
if not os.path.isdir(self.mcu_copro):
|
|
|
|
raise Exception(f'"{self.mcu_copro}" doesn\'t exists')
|
2023-05-08 21:30:33 +00:00
|
|
|
try:
|
|
|
|
cube_manifest_file = os.path.join(self.cube_dir, "VERSION")
|
|
|
|
with open(cube_manifest_file, "r") as cube_manifest:
|
|
|
|
cube_version = cube_manifest.read().strip()
|
|
|
|
except IOError:
|
|
|
|
raise Exception(f"Failed to read version from {cube_manifest_file}")
|
|
|
|
|
|
|
|
if not cube_version.startswith("v"):
|
|
|
|
raise Exception(f"Invalid cube version: {cube_version}")
|
|
|
|
cube_version = cube_version[1:]
|
|
|
|
|
2023-04-24 07:19:36 +00:00
|
|
|
if cube_version != reference_cube_version:
|
2023-05-08 21:30:33 +00:00
|
|
|
raise Exception(
|
|
|
|
f"Unsupported cube version: {cube_version}, expecting {reference_cube_version}"
|
|
|
|
)
|
2021-09-13 09:52:50 +00:00
|
|
|
self.version = cube_version
|
|
|
|
|
2022-10-18 12:13:28 +00:00
|
|
|
def _getFileName(self, name):
|
|
|
|
return posixpath.join(self.COPRO_TAR_DIR, name)
|
2022-10-12 16:12:05 +00:00
|
|
|
|
2023-06-06 19:33:04 +00:00
|
|
|
def _addFileReadPermission(self, tarinfo):
|
|
|
|
tarinfo.mode = 0o644
|
|
|
|
return tarinfo
|
|
|
|
|
2021-09-13 09:52:50 +00:00
|
|
|
def addFile(self, array, filename, **kwargs):
|
|
|
|
source_file = os.path.join(self.mcu_copro, filename)
|
2023-06-06 19:33:04 +00:00
|
|
|
self.output_tar.add(
|
|
|
|
source_file,
|
|
|
|
arcname=self._getFileName(filename),
|
|
|
|
filter=self._addFileReadPermission,
|
|
|
|
)
|
2022-10-12 16:12:05 +00:00
|
|
|
array.append({"name": filename, "sha256": file_sha256(source_file), **kwargs})
|
|
|
|
|
|
|
|
def bundle(self, output_file, stack_file_name, stack_type, stack_addr=None):
|
2022-10-13 15:05:07 +00:00
|
|
|
self.output_tar = tarfile.open(output_file, "w:gz", format=tarfile.USTAR_FORMAT)
|
2022-10-18 12:13:28 +00:00
|
|
|
fw_directory = tarfile.TarInfo(self.COPRO_TAR_DIR)
|
2023-06-06 19:33:04 +00:00
|
|
|
fw_directory.mode = 0o755
|
2022-10-18 12:13:28 +00:00
|
|
|
fw_directory.type = tarfile.DIRTYPE
|
|
|
|
self.output_tar.addfile(fw_directory)
|
2021-09-13 09:52:50 +00:00
|
|
|
|
2022-04-27 15:53:48 +00:00
|
|
|
stack_file = os.path.join(self.mcu_copro, stack_file_name)
|
2021-09-13 09:52:50 +00:00
|
|
|
# Form Manifest
|
|
|
|
manifest = dict(MANIFEST_TEMPLATE)
|
|
|
|
manifest["manifest"]["timestamp"] = timestamp()
|
2022-04-27 15:53:48 +00:00
|
|
|
copro_bin = CoproBinary(stack_file)
|
|
|
|
self.logger.info(f"Bundling {copro_bin.img_sig.get_version()}")
|
|
|
|
stack_type_code = get_stack_type(stack_type)
|
|
|
|
manifest["copro"]["radio"]["version"].update(
|
|
|
|
{
|
|
|
|
"type": stack_type_code,
|
|
|
|
"major": copro_bin.img_sig.version_major,
|
|
|
|
"minor": copro_bin.img_sig.version_minor,
|
|
|
|
"sub": copro_bin.img_sig.version_sub,
|
|
|
|
"branch": copro_bin.img_sig.version_branch,
|
|
|
|
"release": copro_bin.img_sig.version_build,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
if not stack_addr:
|
|
|
|
stack_addr = copro_bin.get_flash_load_addr()
|
|
|
|
self.logger.info(f"Using guessed flash address 0x{stack_addr:x}")
|
|
|
|
|
2021-09-13 09:52:50 +00:00
|
|
|
# Old FUS Update
|
|
|
|
self.addFile(
|
|
|
|
manifest["copro"]["fus"]["files"],
|
|
|
|
"stm32wb5x_FUS_fw_for_fus_0_5_3.bin",
|
|
|
|
condition="==0.5.3",
|
|
|
|
address="0x080EC000",
|
|
|
|
)
|
|
|
|
# New FUS Update
|
|
|
|
self.addFile(
|
|
|
|
manifest["copro"]["fus"]["files"],
|
|
|
|
"stm32wb5x_FUS_fw.bin",
|
|
|
|
condition=">0.5.3",
|
|
|
|
address="0x080EC000",
|
|
|
|
)
|
|
|
|
# BLE Full Stack
|
|
|
|
self.addFile(
|
|
|
|
manifest["copro"]["radio"]["files"],
|
2022-04-27 15:53:48 +00:00
|
|
|
stack_file_name,
|
|
|
|
address=f"0x{stack_addr:X}",
|
2021-09-13 09:52:50 +00:00
|
|
|
)
|
2022-10-12 16:12:05 +00:00
|
|
|
|
|
|
|
# Save manifest
|
|
|
|
manifest_data = json.dumps(manifest, indent=4).encode("utf-8")
|
|
|
|
info = tarfile.TarInfo(self._getFileName("Manifest.json"))
|
|
|
|
info.size = len(manifest_data)
|
|
|
|
self.output_tar.addfile(info, BytesIO(manifest_data))
|
|
|
|
self.output_tar.close()
|