|
Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
|
Status: Accepted - applied to all 9 backend-bearing modules Date: 2026-08-06 Applies to: safeAPIFreamwork, every OAL service with a backend vtable (ADR-005): timer, nvm, memory, task, ipc, log, reboot, netlink, clocksync.
Feedback on the framework was that SAPI has become too complicated, and the first concrete symptom named was header structure: every OAL service (ADR-005) currently declares two very different audiences' APIs in one file. Using sapi_timer.h as the representative example, a single 155-line header held both:
A consuming application has no reason to see the vtable shape at all; it never populates one or calls the register function. Mixing the two in one file makes the header read as more complex than the piece of it any given reader actually needs, and makes it easy for consumer code to (accidentally or not) reach into backend-only internals.
A separate top-level tree (not a subfolder of include/safeapi/<feature>/) was chosen over a same-directory _backend.h suffix so the two audiences are physically, not just conventionally, separated - an integrator can grep or browse include/safeapi_backend/ to see exactly the surface they need to implement, without any consumer-only material mixed in, and vice versa. The cost is a second top-level directory and a second install(DIRECTORY ...) rule per distributable tree; both are one-time, structural costs, not ones that recur per feature added later.
Given the scale of this change (9 modules, every downstream include), sapi_timer was split first as a pilot and verified (framework unit tests for timer/watchdog/log/dual-negotiator rebuilt and passed; the full safeAPIRBC2oo2 8-process demo rebuilt from source and re-run with identical behavior to before the split). The same mechanical split - move the vtable struct and _register_backend() declaration out, add the new backend header, update every file that referenced the vtable type - was then applied unchanged to the remaining eight: nvm, memory, task, ipc, log, reboot, netlink, and clocksync. No per-module wrinkle turned up (no service has more than one vtable; sapi_clocksync was the only header where the backend material was interleaved with consumer functions rather than trailing them, but the split was still mechanical). Verified the same way as the pilot: every affected framework unit test (16 total: status, buffer, cast, safestate, string, timer, nvm, reboot, vital_channel, clocksync, checkpoint, netlink, watchdog, appmanager, log, and the three dual/ tests) rebuilt via manual gcc and passed, and a full safeAPIRBC2oo2 rebuild + live 8-process WEST/EAST demo run showed 0 errors and identical AGREE/checkpoint/negotiation behavior to before the split.
All 9 backend-bearing modules are split as of this update: include/safeapi/<feature>/sapi_<feature>.h (consumer) and include/safeapi_backend/<feature>/sapi_<feature>_backend.h (backend) exist side by side for timer, nvm, memory, task, ipc, log, reboot, netlink, and clocksync. safeAPIRBC2oo2's POSIX backend (include/safeapi/posix_backend/sapi_posix_backend.h) includes both headers for every service it implements.