From f89d069ab1c8f22557e36f8271cb4e60e78d6362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Fri, 17 Nov 2023 19:04:43 +0100 Subject: [PATCH] read and parse image binary header during firmware upload --- src/c3nav/mesh/dataformats.py | 8 +++++++- src/c3nav/mesh/models.py | 3 +-- src/c3nav/mesh/newapi.py | 13 ++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/c3nav/mesh/dataformats.py b/src/c3nav/mesh/dataformats.py index bf4f05a8..5194ea7d 100644 --- a/src/c3nav/mesh/dataformats.py +++ b/src/c3nav/mesh/dataformats.py @@ -1,6 +1,7 @@ import re from dataclasses import dataclass, field from enum import IntEnum, unique +from typing import BinaryIO, Self from c3nav.api.utils import EnumSchemaByNameMixin from c3nav.mesh.baseformats import (BoolFormat, EnumFormat, FixedHexFormat, FixedStrFormat, SimpleFormat, StructType, @@ -227,7 +228,7 @@ class FirmwareImageFileHeader(StructType): class FirmwareImageExtendedFileHeader(StructType): wp_pin: int = field(metadata={"format": SimpleFormat('B')}) drive_settings: int = field(metadata={"format": SimpleFormat('3B')}) - chip_id: ChipType = field(metadata={"format": EnumFormat('H')}) + chip: ChipType = field(metadata={"format": EnumFormat('H')}) min_chip_rev_old: int = field(metadata={"format": SimpleFormat('B')}) min_chip_rev: tuple[int, int] = field(metadata={"format": ChipRevFormat()}) max_chip_rev: tuple[int, int] = field(metadata={"format": ChipRevFormat()}) @@ -241,3 +242,8 @@ class FirmwareImage(StructType): ext_header: FirmwareImageExtendedFileHeader first_segment_headers: tuple[int, int] = field(metadata={"format": SimpleFormat('2I')}, repr=False) app_desc: FirmwareAppDescription + + @classmethod + def from_file(cls, file: BinaryIO) -> Self: + result, data = cls.decode(file.read(FirmwareImage.get_min_size())) + return result diff --git a/src/c3nav/mesh/models.py b/src/c3nav/mesh/models.py index ca62b90b..62a793b8 100644 --- a/src/c3nav/mesh/models.py +++ b/src/c3nav/mesh/models.py @@ -412,8 +412,7 @@ class FirmwareBuild(models.Model): @cached_property def firmware_image(self) -> FirmwareImage: - firmware_image, remaining = FirmwareImage.decode(self.binary.open('rb').read()[:FirmwareImage.get_min_size()]) - return firmware_image + return FirmwareImage.from_file(self.binary.open('rb')) class FirmwareBuildBoard(models.Model): diff --git a/src/c3nav/mesh/newapi.py b/src/c3nav/mesh/newapi.py index e63e323b..55427715 100644 --- a/src/c3nav/mesh/newapi.py +++ b/src/c3nav/mesh/newapi.py @@ -88,8 +88,6 @@ def firmware_project_description(request, firmware_id: int, variant: str): class UploadFirmwareBuildSchema(Schema): variant: str = APIField(..., example="c3uart") - chip: ChipType = APIField(..., example=ChipType.ESP32_C3.name) - sha256_hash: str = APIField(..., regex=r"^[0-9a-f]{64}$") boards: list[BoardType] = APIField(..., example=[BoardType.C3NAV_LOCATION_PCB_REV_0_2.name, ]) project_description: dict = APIField(..., title='project_description.json contents') uploaded_filename: str = APIField(..., example="firmware.bin") @@ -143,16 +141,21 @@ def firmware_upload(request, firmware_data: UploadFirmwareSchema, binary_files: # if sha256_bin_file != build_data.sha256_hash: # raise ValueError + try: + image = FirmwareImage.from_file(binary_files_by_name[build_data.uploaded_filename].open('rb')) + except ValueError: + raise APIRequestValidationFailed(f"Can't parse binary image {build_data.uploaded_filename}") + build = version.builds.create( variant=build_data.variant, - chip=build_data.chip, - sha256_hash=build_data.sha256_hash, + chip=image.ext_header.chip.name, + sha256_hash=image.app_desc.app_elf_sha256, project_description=build_data.project_description, binary=binary_files_by_name[build_data.uploaded_filename], ) for board in build_data.boards: - build.firmwarebuildboard_set.create(board=board) + build.firmwarebuildboard_set.create(board=board.name) except IntegrityError: raise APIConflict('Firmware version already exists.')