38 lines
1.2 KiB
Python
38 lines
1.2 KiB
Python
"""Synthetic ninlight OTA images: 56-byte W600 header + gzip stream + 512-byte NINL trailer.
|
|
|
|
The layout mirrors ninlight-firmware/tools/mkimage/nl_mkimage.py and was checked against a real
|
|
image (spec §2). Tests build their own images instead of copying firmware binaries.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import gzip
|
|
import hashlib
|
|
|
|
CONTENT_WITH_SSID = b"\x00boot\x00ninIOT\x00ninlight-%s\x00"
|
|
CONTENT_WITHOUT_SSID = b"\x00boot\x00ninlight-%s\x00"
|
|
|
|
|
|
def build_payload(content: bytes) -> bytes:
|
|
return b"\xab" * 56 + gzip.compress(content, mtime=0)
|
|
|
|
|
|
def build_image(
|
|
device_type: str = "gu10_rgb",
|
|
version: str = "0.3.8-47-g71a57",
|
|
*,
|
|
content: bytes = CONTENT_WITH_SSID,
|
|
payload: bytes | None = None,
|
|
magic: bytes = b"NINL",
|
|
fmt: int = 1,
|
|
corrupt_hash: bool = False,
|
|
) -> bytes:
|
|
body = payload if payload is not None else build_payload(content)
|
|
trailer = bytearray(b"\xff" * 512)
|
|
trailer[0:4] = magic
|
|
trailer[4] = fmt
|
|
trailer[5:21] = device_type.encode().ljust(16, b"\x00")
|
|
trailer[21:37] = version.encode().ljust(16, b"\x00")
|
|
trailer[37:69] = bytes(32) if corrupt_hash else hashlib.sha256(body).digest()
|
|
return body + bytes(trailer)
|