read and parse image binary header during firmware upload

This commit is contained in:
Laura Klünder 2023-11-17 19:04:43 +01:00
parent 14e39b2377
commit f89d069ab1
3 changed files with 16 additions and 8 deletions

View file

@ -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

View file

@ -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):

View file

@ -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.')