Skip to content

Board::Init() cannot report which peripheral failed #43

Description

@nehalkpatel

Problem

board::Board::Init() returns std::expected<void, common::Error>, and
common::Error is a plain 12-value enum with no payload
(src/libs/common/error.hpp). So a board with several off-chip devices can
report that bring-up failed, but not which device failed or why.

With one hardware board and no off-chip peripherals this is invisible. It stops
being invisible as soon as stage 2 has real occupants — an I2C sensor, a SPI
flash, a UART-attached radio. A kTimeout from Init() would then mean "one of
four things did not answer", which is not much better than a hang for someone
holding the board.

docs/BOOT_FLOW.md records this under Known gaps, and it is the first of those
gaps to land: it is a prerequisite for off-chip bring-up being useful, not a
consequence of it.

Made worse by having nowhere to report to

Even a rich error has no destination during bring-up. main.cpp stashes the
error where a debugger can read it and halts, because the console is a stage 3
resource that the application brings up — mcu::Uart::Init is called by the
app, deliberately, so the board cannot have a console while it is initialising.

So this issue is really two questions, and they may want different answers:

  1. What does a failing Board::Init() carry?
  2. Where does that go on a board whose only output device is not up yet?

Options

None obviously right, which is why this is an issue.

  1. Widen common::Error with peripheral-specific values (kI2CSensorAbsent,
    kFlashIdMismatch, ...). Cheap, no signature change, and it does not scale:
    the enum becomes a registry of every device any board might carry.
  2. A richer error type for bring-up only — a small struct carrying which
    peripheral and an underlying common::Error. Keeps common::Error clean,
    but introduces a second error vocabulary, and the peripheral identifier has
    to be nameable without allocation.
  3. Per-peripheral accessors that can fail, i.e. the board::Board narrowing
    already deferred to Milestone 3 — I2C1() -> std::expected<mcu::I2CController&, Error>.
    Then a device that did not come up is reported at the point of use, by the
    thing that knows what it wanted. Largest change, and it is already on the
    roadmap for other reasons.
  4. A bring-up log rather than a return value — record what failed into a
    buffer the application can print once it has a console. Solves question 2
    directly, and is the only option here that does.

Options 3 and 4 are close to orthogonal and might both be right.

Not this

Widening common::Error device by device as devices are added. That is option 1
arrived at by accident rather than on purpose, and the enum is shared with every
non-board caller.

Anchored in the code

  • src/libs/common/error.hpp — the enum
  • src/libs/board/board.hppInit()'s signature and the two-phase contract
  • src/libs/board/stm32f767zi_nucleo/main.cpp:19-27 — the halt-with-error-in-a-register path
  • docs/BOOT_FLOW.md — Known gaps
  • docs/PROJECT_PLAN.md — Milestone 3, alongside the board::Board narrowing

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions