Repository navigation
Conversation
…board bootloader flash size Replace the single 1.x table with partitions/ota_4mb.csv and ota_8mb.csv (2.x layouts: bigger app slots, a dedicated cfg NVS partition, a flat www image of type 0x40 instead of littlefs static0/config). The old table stays under partitions/legacy/ as the reference for fielded hubs and as a migration test fixture. A board's table follows from its flash size (scripts/utils/partitions.py), so board files no longer name one and the table never splits a build variant. scripts/package_boards.py now writes each board's partition-table.bin itself (a byte-identical reimplementation of gen_esp32part.py, MD5 entry included, so CI needs no ESP-IDF for it) and stamps the board's flash size into the bootloader header: the ROM and the second-stage bootloader size the flash from that header and would refuse the 8 MB table behind a bootloader compiled at the variant's 4 MB. gen_staticfs.py packs the frontend into the www format (scripts/utils/wwwimage.py: sorted directory, 4-byte aligned bodies, truncated sha256 over the body) instead of a littlefs image, dropping the littlefs-python dependency. One unpadded image serves every board and is checked to fit the smallest www partition.
components/www parses the flat www image (scripts/utils/wwwimage.py writes it): a sorted directory of 4-byte aligned bodies behind a header with a truncated SHA-256 over everything after it. Every field is checked before the image is used, so a bad image means "no portal assets", never a partially trusted one. WwwPartition maps the type-0x40 partition once and serves by pointer. components/partition_table parses the binary table at 0x8000 (MD5 entry included), tells the 1.x layout from the 2.x ones, and checks a staged table against every invariant the over-the-air table rewrite relies on: nvs and otadata unmoved, cfg and www present, geometry the bootloader accepts, a slot for the running image, a live 1.x table, and a bootloader header that declares enough flash. Both are pure C++ over byte spans with host suites; their fixtures are produced at configure time by the same Python that writes the release artifacts, so the two implementations are checked against each other.
ESP-IDF owns the component name partition_table: a project component of that name shadows it, and every partition_table_get_partition_info() call in ESP-IDF's own CMake (app_update, esptool_py) fails to configure.
Client::Head reports whether a URL answers and its Content-Length without downloading it: the layout migration checks that the 2.0.0 artifacts are reachable before it touches flash. The connection setup Download already had (reuse the kept-alive handle, reconnect once if the server closed it) moves into openRequest so both share it. A HEAD response has no body to drain, so the connection is dropped rather than kept alive afterwards.
The www host suite packs its fixtures at configure time with the same packer the build uses, so the C++ parser and the Python writer are checked against each other.
The config component no longer owns any settings. It is a framework for keeping them in NVS: - config/Nvs.h: typed access to one NVS namespace (tri-state reads, writes that skip unchanged values), plus copying and comparing whole namespaces. - config/Section.h: Section<T>, one module's settings with a RAM cache, writers serialized across sections, saves of the changed keys only, and publication after the save. Every section links itself into an ordered registry at static initialization. - config/Store.h: picks the store (the `cfg` partition, or the shared `nvs` on the 1.x layout), moves the shared copy into `cfg` key by key and verifies it, fills an empty store from the 1.x littlefs file or the defaults, loads every section (one unreadable section is reset alone), factory reset, and the whole-config JSON for jsonconfig, which every section parses before any of them saves. - config/Wire.h: the HubConfig wire form for the local protocol's Ready message and rawconfig, assembled from the sections' own ToFlatbuffers, and HubConfig -> jsonconfig JSON, which is also how the 1.x config file is imported (with the 1.5.x flipped-default booleans resolved there, in one place). Each module defines its own section, NVS keys and accessors: device_control: rf, estop core: wifi, backend, otaUpdate captive_portal: captivePortal serial_console: serialInput otaUpdate lives in core, the lowest component that uses it (the gateway reports the step, the portal edits the channel, ota runs updates above both). The accessors keep their names in the OpenShock::Config namespace, so call sites change only their includes. RootConfig, ConfigBase<T> and the sections' FromFlatbuffers are gone. Chipset.h includes hal/gpio_types.h instead of driver/gpio.h: it only needs the types, and the driver header is what made the config host suite depend on ESP-IDF's driver mocks. The config host suite compiles the framework with every module's section and runs them on ESP-IDF's real NVS over the linux flash emulation: 62 cases, among them the 1.x import of the Arduino fixtures, the move from the shared nvs, the registry order, saves that write only what changed, and a 40-credential config the 1.x partition could never hold.
A 1.x hub installs the 1.9.x pivot with its own OTA code, which flashes the staticfs artifact into its littlefs static0 partition and aborts the update unless that partition then mounts. A flat www image as 1.9.x's staticfs would make the pivot uninstallable from the field. gen_staticfs.py --legacy-output packs the same assets as the 1.x littlefs image (/www/<path>.gz, sized for static0), the build-staticfs action builds both images, and the publish step picks the staticfs file by the release's major version: staticfs.bin for 1.x, www.bin from 2.0.0 on. littlefs-python comes back as a build dependency for that output only; both go away with release/1.9.
The captive portal maps the www partition once and serves each asset straight from the flash mapping, with its gzip flag, a long cache lifetime for content-addressed assets, and an ETag from the image's body hash. On the 1.x layout, which has no www partition, it falls back to the littlefs static0 image as before. The OTA update flashes staticfs into whichever of the two the table has and checks it in that format, skips the flash when the www image on flash already has the release's hash, and parses the optional partitions artifact (this board's partition table) for the layout migration. TryStartMigrationUpdate lets the hub install a version on its own initiative: the backend-management and manual-approval settings do not hold it back, disabling OTA updates still does.
components/migration is the 1.9.x pivot's boot chain (docs/STORAGE.md). On the 1.x table, once online, it checks that the target release (CONFIG_OPENSHOCK_MIGRATION_TARGET_VERSION, 2.0.0) carries this board's partition table and that its app and www image answer, downloads the table into RAM, checks its SHA-256 and every invariant in partition_layout, and on any failure stays on the 1.x layout and retries later. Running from the 1.x app1 it first hops to app0 (4 MB) or copies itself to where the new table puts app1 (8 MB). It writes the target's www image where the new table puts www, holds config writes, closes NVS, writes the table sector through the OTA path, reads it back and restarts. On the 2.x table it drops the WiFi driver's stale store and any 1.x fragment in the moved slot, then installs the target version; if that rolls back, the chain stops. A 2.x build only reports the layout. sysinfo prints the layout, the bootloader header's flash size and the config store. docs/STORAGE.md describes the tables, the config store and its sections, the www image, the migration and the serial recovery for the one unrecoverable window (the table sector's erase-to-write).
The estop section's namespace keeps a latched (u8) key beside the section's settings. The E-Stop task writes it on every activation and every clear, after the change is already in effect, and never waits for another config writer. Init reads it before anything can transmit and keeps a latched E-Stop active until it is cleared with the button. A missing key reads as not latched and a read error as latched. A latch on a hub whose E-Stop is disabled is dropped, since nothing could clear it. A factory reset clears it.
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
Cpp-Linter Report
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.