Firmware development framework for STM32 and RP2040 hardware, including CAN and DCS-BIOS support.

Install

mkdir -p .claude/skills/firmware && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16694" && unzip -o skill.zip -d .claude/skills/firmware && rm skill.zip

Installs to .claude/skills/firmware

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

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.
406 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Implement CAN protocol for OpenSkyhawk firmware
  • Assign NODE_ID for STM32 and RP2040 devices
  • Manage MCP23017 and ADS1115 via PanelGroup library
  • Ensure Doxygen style docblocks for public APIs
  • Synchronize firmware changes with authoritative specs

How it works

This skill guides firmware development for OpenSkyhawk devices by referencing authoritative specifications, enforcing CAN protocol, NODE_ID assignments, and using specific libraries for hardware interaction, while maintaining documentation and code structure.

Inputs & outputs

You give it
Firmware changes for STM32 or RP2040 devices
You get back
Updated OpenSkyhawk firmware adhering to CAN protocol, NODE_ID assignments, and API contracts

When to use firmware

  • Write firmware for PanelBridge
  • Configure SimGateway node
  • Implement CAN protocol
  • Integrate DCS-BIOS

About this skill

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 made
  • 01-system-overview.md — topology, library roles, data-flow narrative
  • 02-can-protocol.md — CAN frame IDs, NODE_ID, ControlPacket wire format, TX queue
  • 03-uart-usb-hid-protocol.md — UART mux, HID frame format, USB identity
  • 04-dcs-bios-integration.mdcontrolId space, DCSIN_*, input-map generator rules
  • 05-panelgroup-api.mdPinRef, MCP23017 management, all input & output classes
  • 06-panelbridge-api.md — node tracking, export listener, input dispatch, SYNC_REQ
  • 07-simgateway-api.mdHIDAxis/HIDButton, relay contract, HID dispatch
  • 08-hardware-firmware-contracts.md — STM32 pin assignments, DRV8833 ~SLEEP, ADS1115
  • 09-startup-resync-diagnostics.md — boot sequences, SYNC_REQ/READY, DIAG frames
  • 10-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; use STM32F103CB (128 KB) only where flash demands it (PanelBridge runs the full DCS-BIOS input map). Use full part numbers in prose, never the CBT6 ordering code or C8/CB shorthand.
  • NODE_ID: compile-time only — build_flags = -DNODE_ID=N in platformio.ini, never a #define in main.cpp. 0 = PanelBridge; 1–63 = PanelGroup nodes. Claim the next free number in Firmware/NODE_IDS.md in the same PR that starts the work; never reuse one. tools/check_node_ids.py enforces this in CI.
  • Expander access is via classes, not registers: the PanelGroup library owns MCP23017 integration; ADS1115 via ADS1115.h. Instantiate input classes (Switch2Pos, Switch3Pos, RotarySwitch, SwitchMultiPos, AnalogInput, RotaryEncoder, …) and output classes (LED, IntegerOutput, SwitecX25Output, …) on a PinRef. The electrical wiring of those parts belongs to the pcb-design skill.
  • Timing: each class calls millis() directly and keeps its own uint32_t timestamp — no shared clock.
  • Docblocks: Doxygen style on every public class/method/enum/non-obvious constant (@brief, @param with units, @return, @note for ISR/timing constraints). Private members use plain //.
  • Library + test layout: each library is Firmware/Libraries/<Name>/ with a library.json; its tests are a standalone project Firmware/Tests/<Name>/ using src_dir = tests, an [env_base] section, and one build_src_filter per scenario. See TechSpec/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.h is HID controlId constants only; CANProtocol.h owns CAN frame transport (incl. NodeHealthPayload). The cross-node status contract — NODE_STATUS_* (DCS-BIOS reporting), NodeHealthFlag, NodeFaultCode, and FaultSource — lives in the neutral NodeStatus library, 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) inherits OpenSkyhawk::FaultSource (NodeStatus.h), self-registers, and reports cached faultCode() (a NodeFaultCode) + local faultDetail() (DiagSerial-only string, never on the wire). The node-level aggregator walks FaultSource::head() → sets HEALTH_n.faultId + DEGRADED. OutputBase gets 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 #include of 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, #define contract — updates the authoritative FirmwarePlan/ + 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 = earlephilhower core with -DUSE_TINYUSB.
  • C++ standard: any project using DrumDisplay needs -std=gnu++20 + build_unflags = -std=gnu++17 — its DrumReadout descriptors are C++20 designated initializers. Already baked into the PanelGroup scaffold 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.

When not to use it

  • When working on hardware design (pcb-design skill)
  • When the firmware is not for OpenSkyhawk devices
  • When the authoritative specs are not available

Limitations

  • MCU variant: STM32F103C8 is the default for CAN avionics nodes.
  • NODE_ID: compile-time only.

How it compares

This approach provides specific guidelines and conventions for OpenSkyhawk firmware development, including a three-tier architecture and detailed API contracts, unlike general embedded systems programming.

Compared to similar skills

firmware side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
firmware (this skill)01moNo flagsAdvanced
unity-developer1424moNo flagsAdvanced
unity-mcp-orchestrator174moNo flagsIntermediate
arm-cortex-expert294moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

unity-developer

sickn33

Build Unity games with optimized C# scripts, efficient rendering, and proper asset management. Masters Unity 6 LTS, URP/HDRP pipelines, and cross-platform deployment. Handles gameplay systems, UI implementation, and platform optimization. Use PROACTIVELY for Unity performance issues, game mechanics, or cross-platform builds.

142357

unity-mcp-orchestrator

CoplayDev

Orchestrate Unity Editor via MCP (Model Context Protocol) tools and resources. Use when working with Unity projects through MCP for Unity - creating/modifying GameObjects, editing scripts, managing scenes, running tests, or any Unity Editor automation. Provides best practices, tool schemas, and workflow patterns for effective Unity-MCP integration.

1795

arm-cortex-expert

sickn33

Senior embedded software engineer specializing in firmware and driver development for ARM Cortex-M microcontrollers (Teensy, STM32, nRF52, SAMD). Decades of experience writing reliable, optimized, and maintainable embedded code with deep expertise in memory barriers, DMA/cache coherency, interrupt-driven I/O, and peripheral drivers.

2975

implementing-jsc-classes-cpp

oven-sh

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

15

rsyslog-module

rsyslog

Encodes technical requirements for rsyslog modules, including concurrency, metadata, and initialization.

14

server-tick

dadbodgeoff

Server-authoritative tick system for multiplayer games with lag compensation, anti-cheat validation, and deterministic physics. Prevents speed hacks and teleports while keeping gameplay fair for high-latency players.

10

Search skills

Search the agent skills registry