name: firmware description: OpenSkyhawk firmware — STM32 (PanelBridge, PanelGroup) and RP2040 (SimGateway). Use when writing or changing firmware, PlatformIO projects, CAN protocol, NODE_ID assignment, DCS-BIOS integration, HID, panel sketches, shared libraries or their test sketches, or interacting with MCP23017/ADS1115 through the firmware classes (PanelGroup input/output classes). PanelGroup work is the most common interaction.
Firmware
Three-tier architecture:
PC ──USB HID + USB CDC(250k)── RP2040 SimGateway ──UART 250k── STM32 PanelBridge (NODE 0, CAN master)
└─CAN 500k─ PanelGroup nodes (NODE 1–63)
Authoritative spec — route here, don't bulk-load
Firmware/ScratchPad/FirmwarePlan/ is the authoritative firmware specification (the what:
contracts, data flows, decisions) and supersedes any firmware content in docs/_source/.
Firmware/ScratchPad/TechSpec/ holds the how (public API, class structure, method signatures).
Open the one relevant doc via the maps below rather than reading everything.
FirmwarePlan document map (read FirmwarePlan/README.md for the full index):
00-decisions.md— why each choice was made01-system-overview.md— topology, library roles, data-flow narrative02-can-protocol.md— CAN frame IDs,NODE_ID,ControlPacketwire format, TX queue03-uart-usb-hid-protocol.md— UART mux, HID frame format, USB identity04-dcs-bios-integration.md—controlIdspace,DCSIN_*, input-map generator rules05-panelgroup-api.md—PinRef, MCP23017 management, all input & output classes06-panelbridge-api.md— node tracking, export listener, input dispatch, SYNC_REQ07-simgateway-api.md—HIDAxis/HIDButton, relay contract, HID dispatch08-hardware-firmware-contracts.md— STM32 pin assignments, DRV8833 ~SLEEP, ADS111509-startup-resync-diagnostics.md— boot sequences, SYNC_REQ/READY, DIAG frames10-implementation-plan.md/11-open-issues.md— phased plan / deferred items
TechSpec: one file per library/class (CANProtocol, STM32Board, PanelBridge,
SimGateway, HIDControls, A4ECGenerator, and PanelGroup/{PinRef, PanelGroup, Inputs/*, Outputs/*}). Each cites its FirmwarePlan section. See TechSpec/README.md.
Availability guard: these specs are committed but may be absent in a partial checkout —
if Firmware/ScratchPad/FirmwarePlan/ is missing, rely on the conventions below plus the
committed code under Firmware/Libraries/.
Durable conventions (always apply)
- MCU variant:
STM32F103C8(64 KB) is the default for CAN avionics nodes; useSTM32F103CB(128 KB) only where flash demands it (PanelBridge runs the full DCS-BIOS input map). Use full part numbers in prose, never theCBT6ordering code orC8/CBshorthand. - NODE_ID: compile-time only —
build_flags = -DNODE_ID=Ninplatformio.ini, never a#defineinmain.cpp. 0 = PanelBridge; 1–63 = PanelGroup nodes. Claim the next free number inFirmware/NODE_IDS.mdin the same PR that starts the work; never reuse one.tools/check_node_ids.pyenforces this in CI. - Expander access is via classes, not registers: the
PanelGrouplibrary owns MCP23017 integration; ADS1115 viaADS1115.h. Instantiate input classes (Switch2Pos,Switch3Pos,RotarySwitch,SwitchMultiPos,AnalogInput,RotaryEncoder, …) and output classes (LED,IntegerOutput,SwitecX25Output, …) on aPinRef. The electrical wiring of those parts belongs to thepcb-designskill. - Timing: each class calls
millis()directly and keeps its ownuint32_ttimestamp — no shared clock. - Docblocks: Doxygen style on every public class/method/enum/non-obvious constant
(
@brief,@paramwith units,@return,@notefor ISR/timing constraints). Private members use plain//. - Library + test layout: each library is
Firmware/Libraries/<Name>/with alibrary.json; its tests are a standalone projectFirmware/Tests/<Name>/usingsrc_dir = tests, an[env_base]section, and onebuild_src_filterper scenario. SeeTechSpec/README.md. - Implementation order (dependencies flow down): HIDControls → A4EC → CANProtocol → STM32Board → PanelBridge / SimGateway → PanelGroup (PinRef → PanelGroup → Inputs/Outputs).
- Header ownership — keep shared headers single-purpose.
HIDControls.his HID controlId constants only;CANProtocol.howns CAN frame transport (incl.NodeHealthPayload). The cross-node status contract —NODE_STATUS_*(DCS-BIOS reporting),NodeHealthFlag,NodeFaultCode, andFaultSource— lives in the neutralNodeStatuslibrary, because every node type shares it (PanelGroup, PanelBridge, PDU) and it's broader than "health." Never shape a cross-node contract around one flavor (PanelGroup.h/OutputBase) or the HID namespace (D14). - Fault sources feed a node aggregator; no producer owns node health. A fault-producing object
(
DrumDisplay, a PDU rail monitor, a PanelBridge host-link watchdog) inheritsOpenSkyhawk::FaultSource(NodeStatus.h), self-registers, and reports cachedfaultCode()(aNodeFaultCode) + localfaultDetail()(DiagSerial-only string, never on the wire). The node-level aggregator walksFaultSource::head()→ setsHEALTH_n.faultId+ DEGRADED.OutputBasegets no fault API — an output is just one possible fault source, not special. - Includes: direct for what you use, but don't couple upward. Prefer a direct
#includeof a symbol's defining header over relying on a fragile transitive path — but if adding that include would drag a low-level/UI class into a heavier or conceptually-wrong layer, that's a signal the symbol is placed wrong (see the two rules above), not that you should hide it behind a transitive include. Don't add an include already reliably provided by a header the file must include anyway. - Spec-sync in the same PR. Any change to a public firmware API — struct/enum, class method,
wire format,
#definecontract — updates the authoritativeFirmwarePlan/+TechSpec/doc in the same PR, listed as a deliverable and self-checked before push. The spec is source of truth; drift defeats it. Grep the old value/claim before pushing. - Toolchain: PlatformIO. STM32 =
platform = ststm32,framework = arduino. RP2040 =earlephilhowercore with-DUSE_TINYUSB. - C++ standard: any project using
DrumDisplayneeds-std=gnu++20+build_unflags = -std=gnu++17— itsDrumReadoutdescriptors are C++20 designated initializers. Already baked into thePanelGroupscaffold template, so B6 sketches get it by default; add it explicitly to a standalone test project. The whole PanelGroup dep stack (U8g2 / MCP23017 / ADS1X15) is gnu++20-clean.
Verify
Build the affected project(s) with platformio run -d <project>; exercise each class in
isolation via its Firmware/Tests/<Name>/ sketch before integration.
Expert Next.js App Router
Developpement
Un skill qui transforme Claude en expert Next.js App Router.
Générateur de README
Developpement
Crée des README.md professionnels et complets pour vos projets.
Rédacteur de Documentation API
Developpement
Génère de la documentation API complète au format OpenAPI/Swagger.