Skip to content

feat: S29.05 PlusFAT-backed store on the FreeRTOS-Plus-TCP BDD target#526

Merged
DavidCozens merged 7 commits into
mainfrom
feat/s29-05-plusfat-media-driver
Jun 4, 2026
Merged

feat: S29.05 PlusFAT-backed store on the FreeRTOS-Plus-TCP BDD target#526
DavidCozens merged 7 commits into
mainfrom
feat/s29-05-plusfat-media-driver

Conversation

@DavidCozens

@DavidCozens DavidCozens commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Purpose

Last functional story of E29 (#525, parent #512). Gives the FreeRTOS-Plus-TCP QEMU BDD target a real FreeRTOS-Plus-FAT-backed store, proving the SolidSyslogFile seam is FS-vendor-portable — ChaN-FatFs on the lwIP target, FreeRTOS-Plus-FAT on the Plus-TCP target — the same way E28 proved the transport seam is TCP-vendor-portable. FatFs relocated to lwIP in S29.01; PlusFAT lands here.

Closes #525.

Change Description

  • FS-mount seam. S29.03 extracted only the network backend behind the pipeline config; both targets shared FatFs so no FS seam was needed yet. This is the first divergence, so BddTargetFreeRtosPipelineConfig gains four hooks (MountStore / UnmountStore / CreateStoreFile / DestroyStoreFile). FatFs logic moved to BddTargetFatFsMount, PlusFAT to BddTargetPlusFatMount; the pipeline no longer includes ff.h/SolidSyslogFatFsFile.h.
  • Shared semihosting media (DRY). The BKPT-0xAB host-file I/O + 8 MiB FAT16 geometry moved out of diskio.c into a shared SemihostingDisk TU, consumed by both the ChaN diskio.c glue and the new FFSemihostingDisk FF_Disk_t driver — so FatFs and PlusFAT runs hit byte-for-byte the same host image.
  • FFSemihostingDisk — FF_Disk_t driver modelled on Plus-FAT's ff_ramdisk.c, but mount-or-format-on-first-use (tries FF_Mount first so a power cycle keeps data; partitions + FF_Format(..., xPreferFAT16) only a fresh image).
  • Plus-TCP target swapmain.c installs the PlusFAT seam; CMakeLists drops all FatFs and compiles the 13 Plus-FAT core sources (relaxed OBJECT lib, -Wno-cpp for ff_fat.c's one-FAT-table #warning); new integrator FreeRTOSFATConfig.h; configNUM_THREAD_LOCAL_STORAGE_POINTERS = 3 (ff_stdio TLS). FFSemihostingDisk.c stays in the strict executable with only -Wno-sign-conversion (Plus-FAT's FF_ERR_* macros carry the high flag bit).
  • ff_fflush defect fix (approved scope expansion). The S29.04 adapter flushed via ff_fflush, which Plus-FAT declares in ff_stdio.h but never defines (PlusFatFake defined it, so host tests passed while the real target failed to link). Switched to FF_FlushCache(Fp->pxIOManager), the real cache-flush primitive (dirent size still committed on Close); fake + the three durability tests updated. This is the one place the host fake masked a real-library gap.
  • Absolute store paths — Plus-FAT ff_stdio accepts only absolute paths at ffconfigHAS_CWD=0, so the shared store prefix became /STORE (valid for ChaN too).
  • Docs — new docs/integrating-plusfat.md; DEVLOG entry.

Test Evidence

  • Host TDDSolidSyslogPlusFatFileTest 30/30 green after the ff_fflushFF_FlushCache swap (fake spy + the three durability tests retargeted: flush-once-on-write, skip-on-incomplete-write, fail-on-flush-error).
  • Cross build — both FreeRTOS targets build; Plus-TCP ELF links; nm confirms FF_FlushCache present, no ff_fflush, no FatFs symbols.
  • On-target BDD (QEMU, Plus-TCP) — full @store suite green: 5 features / 12 scenarios passed, 0 failed (store_and_forward, store_capacity, power_cycle_replay, capacity_threshold, block_lifecycle). power_cycle_replay passing confirms flush-data + commit-size-on-close durability across a graceful restart.
  • lwIP FatFs target stays green with the /STORE prefix and shared SemihostingDisk.
  • Format clean tree-wide; misra_suppressions.txt unchanged (analysis lanes — tidy/iwyu/cppcheck — left to CI per the local-checks budget).

Areas Affected

  • Bdd/Targets/Common/ — new SemihostingDisk, FFSemihostingDisk, BddTargetFatFsMount, BddTargetPlusFatMount; diskio.c + pipeline refactor.
  • Bdd/Targets/FreeRtos/ (Plus-TCP target) — FatFs→PlusFAT swap; Bdd/Targets/FreeRtosLwip/ unchanged behaviour (FatFs via the new shim).
  • Platform/PlusFat/Source/ (Tier 2) — one-line durability fix (FF_FlushCache); Platform/FatFs/ untouched. Core/Tier-1 untouched.
  • Tests/ — PlusFatFake + PlusFat durability tests. Docs.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Filesystem mount/unmount abstraction with FatFs and FreeRTOS-Plus-FAT backends
    • File-backed store with idempotent mount + automatic first-use formatting
    • ARM semihosting host-backed disk driver
    • Pipeline hooks for platform-pluggable filesystem lifecycle
  • Documentation

    • Added FreeRTOS-Plus-FAT integration guide and devlog entry
  • Tests

    • Updated tests to exercise new cache-flush API
  • Chores

    • Build and FreeRTOS config updated for FreeRTOS-Plus-FAT integration

Lift the FatFs-specific mount / format-on-first-use / unmount and the
SolidSyslogFile create/destroy out of BddTargetFreeRtosPipeline into a new
BddTargetFatFsMount shim, reached through four function pointers on
BddTargetFreeRtosPipelineConfig (MountStore / UnmountStore / CreateStoreFile /
DestroyStoreFile). The pipeline no longer includes ff.h or
SolidSyslogFatFsFile.h and is now FS-vendor-agnostic. Both targets still use
FatFs via the shim — no behaviour change; sets up the PlusFAT swap on the
Plus-TCP target.
Lift the BKPT 0xAB trap, the open/read/write/seek/length/close primitives,
the 8 MiB FAT16 geometry, and the open-or-create-sparse image logic out of
diskio.c into a new Bdd/Targets/Common/SemihostingDisk TU. diskio.c now maps
the ChaN-FatFs disk_* contract onto SemihostingDisk_{EnsureReady,IsReady,
Read,Write}, preserving its RES_NOTRDY / RES_PARERR / RES_ERROR distinctions.
This lets the upcoming FreeRTOS-Plus-FAT FF_Disk_t driver share byte-for-byte
the same host image and trap. No behaviour change. Verified both FreeRTOS
cross targets still build.
BLOCKED at link on a pre-existing S29.04 adapter defect — see below.

- FFSemihostingDisk: FF_Disk_t media driver over the shared SemihostingDisk
  (mount-or-format-on-first-use, FAT16, IO-manager cache from heap_4).
- BddTargetPlusFatMount: the Plus-FAT FS-mount seam impl.
- Plus-TCP target main.c: install the PlusFat seam (was FatFs).
- Plus-TCP CMakeLists: drop FatFs (ff.c/ffsystem.c/diskio.c/staging),
  add the 14 Plus-FAT core sources to the relaxed OBJECT lib (+ -Wno-cpp for
  ff_fat.c's one-FAT-table #warning), add the adapter/driver/shim to the strict
  executable (-Wno-sign-conversion only on FFSemihostingDisk.c for Plus-FAT's
  unsigned FF_ERR_* macros).
- FreeRTOSConfig.h: configNUM_THREAD_LOCAL_STORAGE_POINTERS = 3 (ff_stdio TLS).
- New integrator FreeRTOSFATConfig.h.
- Shared pipeline: STORE_PATH_PREFIX "STORE" -> "/STORE" (Plus-FAT ff_stdio
  needs absolute paths with ffconfigHAS_CWD=0; valid for ChaN too). lwIP FatFs
  target still builds green.

The Plus-TCP target COMPILES fully but does NOT LINK: SolidSyslogPlusFatFile.c
calls ff_fflush(), which FreeRTOS-Plus-FAT (SHA 8d38036) only DECLARES in
ff_stdio.h and never defines. PlusFatFake defines it, so S29.04 host tests pass
and masked the gap. Real durability primitive is FF_FlushCache(Fp->pxIOManager).
Fixing it touches the merged S29.04 Tier-2 adapter (+ the fake + host tests),
which the S29.05 AC says to leave untouched — needs David's decision.
ff_fflush is declared in FreeRTOS-Plus-FAT's ff_stdio.h but never defined in
the library (SHA 8d38036) — PlusFatFake defined it, so the S29.04 host tests
passed while the real Plus-TCP target failed to link. Switch the adapter's
per-write durability to FF_FlushCache(Fp->pxIOManager), the actual Plus-FAT
cache-flush primitive (FF_FILE carries pxIOManager; ff_stdio.h pulls ff_ioman.h
+ ff_file.h, so no new includes). The directory-entry size is still committed on
Close. Update PlusFatFake (FF_FlushCache spy replaces ff_fflush) and the three
durability tests. Approved expansion of the S29.05 scope (the adapter was the
one place the host fake masked a real-library gap).

Host: SolidSyslogPlusFatFileTest 30/30 green. Plus-TCP cross target now links;
nm confirms FF_FlushCache present, no ff_fflush, no FatFs symbols.
- docs/integrating-plusfat.md: integrator guide (FF_Disk_t media-driver contract,
  FreeRTOSFATConfig.h + kernel-config requirements, absolute-path convention,
  FF_FlushCache durability + dirent-on-close nuance, heap-is-vendor-scoped note,
  the BDD target as reference integration).
- DEVLOG: S29.05 session entry (prepended).
- clang-format reflow of the two new seam headers' pointer alignment.

misra_suppressions.txt left untouched: misra_renumber proposed no changes; the
AMBIGUOUS pairs it reported are pre-existing cross-run cppcheck variance in Core
headers this story never touched (per the cppcheck-misra-invariant note).
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@DavidCozens, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 14104e95-c30c-4dce-932d-6cdea2fa8cb9

📥 Commits

Reviewing files that changed from the base of the PR and between 4e3d8f8 and 31dcbb8.

📒 Files selected for processing (1)
  • misra_suppressions.txt
📝 Walkthrough

Walkthrough

The PR introduces a filesystem-mount seam in the shared FreeRTOS BDD pipeline, enabling per-target filesystem vendor selection. FatFs is retained for the lwIP target; PlusFAT is introduced for the PlusTCP target. Both use a shared semihosting disk abstraction backed by BKPT 0xAB trap code and 8 MiB FAT16 geometry.

Changes

Pipeline FS-mount seam and refactoring

Layer / File(s) Summary
Pipeline FS-mount seam contract and refactoring
Bdd/Targets/Common/BddTargetFreeRtosPipeline.h, Bdd/Targets/Common/BddTargetFreeRtosPipeline.c
struct BddTargetFreeRtosPipelineConfig gains four function pointers (MountStore, UnmountStore, CreateStoreFile, DestroyStoreFile) that form the FS-mount seam contract. Pipeline store lifecycle now calls through the seam; FatFs-specific includes and EnsureFatFsMounted() removed. Store path changed from relative "STORE" to absolute "/STORE" for platform consistency.

Semihosting disk layer

Layer / File(s) Summary
Semihosting disk interface and primitives
Bdd/Targets/Common/SemihostingDisk.h, Bdd/Targets/Common/SemihostingDisk.c
Shared ARM Cortex-M semihosting BKPT 0xAB trap abstraction: SemihostingDisk_EnsureReady opens or creates 8 MiB host disk image; SemihostingDisk_IsReady, SemihostingDisk_Read, SemihostingDisk_Write provide sector-aligned I/O. Includes BKPT wrapper and per-operation request helpers (OPEN/READ/WRITE/SEEK/FLEN/CLOSE).

FatFs disk layer and mount shim

Layer / File(s) Summary
FatFs diskio.c delegation to semihosting
Bdd/Targets/Common/diskio.c
Refactored to delegate all semihosting I/O to shared SemihostingDisk module. disk_initialize calls SemihostingDisk_EnsureReady(). disk_status, disk_read, disk_write gate on SemihostingDisk_IsReady() and map result codes to FatFs status/result enums. disk_ioctl uses SemihostingDisk geometry constants.
FatFs mount seam implementation
Bdd/Targets/Common/BddTargetFatFsMount.h, Bdd/Targets/Common/BddTargetFatFsMount.c
Implements FS-mount seam for FatFs: BddTargetFatFsMount_Mount is idempotent via fatfsMounted flag, mounts via f_mount, formats with f_mkfs (FAT16 config) on first use when filesystem not found, returns false on failure. BddTargetFatFsMount_Unmount conditionally unmounts. File creation/destruction delegate to SolidSyslogFatFsFile adapter.

Plus-FAT media driver and mount shim

Layer / File(s) Summary
Plus-FAT semihosting media driver
Bdd/Targets/Common/FFSemihostingDisk.h, Bdd/Targets/Common/FFSemihostingDisk.c
FF_Disk_t media driver for Plus-FAT: FFSemihostingDisk_Mount initializes disk structure, wires ReadBlocks/WriteBlocks callbacks to semihosting, attempts FF_Mount, and on failure calls PartitionAndFormat (FAT16) then remounts. Block callbacks validate disk signature and delegate to SemihostingDisk_Read/SemihostingDisk_Write, mapping outcomes to Plus-FAT error codes. FFSemihostingDisk_Unmount removes mount and cleans up IO manager.
Plus-FAT mount seam implementation
Bdd/Targets/Common/BddTargetPlusFatMount.h, Bdd/Targets/Common/BddTargetPlusFatMount.c
Implements FS-mount seam for Plus-FAT: thin wrappers around FFSemihostingDisk_Mount/FFSemihostingDisk_Unmount and SolidSyslogPlusFatFile file adapter lifecycle functions.

Plus-FAT cache-flush update

Layer / File(s) Summary
FF_FlushCache durability change and test support
Platform/PlusFat/Source/SolidSyslogPlusFatFile.c, Tests/Support/PlusFatFakes/Interface/PlusFatFake.h, Tests/Support/PlusFatFakes/Source/PlusFatFake.c, Tests/PlusFat/SolidSyslogPlusFatFileTest.cpp
SolidSyslogPlusFatFile_Write replaces ff_fflush(self->Fp) with FF_FlushCache(self->Fp->pxIOManager) targeting the IO-manager cache directly. Test fake PlusFatFake replaces ff_fflush tracking with FF_FlushCache tracking (PlusFatFake_SetFlushCacheFails, PlusFatFake_FlushCacheCallCount, new FF_FlushCache impl). Tests updated to verify cache-flush behavior.

Build and runtime configuration

Layer / File(s) Summary
CMake migration from staged FatFs to non-staged Plus-FAT
Bdd/Targets/FreeRtos/CMakeLists.txt, Bdd/Targets/FreeRtosLwip/CMakeLists.txt
PlusTCP target: introduces FREERTOS_PLUS_FAT_PATH environment requirement, removes FatFs staging, adds Plus-FAT upstream ff_*.c sources to relaxed-warning OBJECT library, adds Plus-FAT-specific adapter and disk-driver modules, updates include paths, adds sign-conversion warning relaxation for FFSemihostingDisk.c. lwIP target: adds SemihostingDisk.c and BddTargetFatFsMount.c to executable sources.
FreeRTOS and target configuration
Bdd/Targets/FreeRtos/FreeRTOSConfig.h, Bdd/Targets/FreeRtos/FreeRTOSFATConfig.h, Bdd/Targets/FreeRtos/main.c, Bdd/Targets/FreeRtosLwip/main.c
FreeRTOSConfig.h adds configNUM_THREAD_LOCAL_STORAGE_POINTERS = 3 for Plus-FAT ff_stdio layout. New FreeRTOSFATConfig.h defines byte order and thread-local storage base index. PlusTCP main.c includes BddTargetPlusFatMount.h and wires its mount/unmount/file functions into pipeline config. lwIP main.c includes BddTargetFatFsMount.h and wires its functions into pipeline config.

Documentation and changelog

Layer / File(s) Summary
Integration guide and devlog
docs/integrating-plusfat.md, DEVLOG.md
New docs/integrating-plusfat.md describes SolidSyslogPlusFatFile placement, required Plus-FAT sources, FF_Disk_t media-driver contract, configuration headers (FreeRTOSFATConfig.h, relevant FreeRTOSConfig.h knobs), absolute-path conventions, cache-flush durability semantics (write-time cache flush, close-time directory commit, no per-file flush), and vendor-scoped heap allocation. DEVLOG.md entry documents FS-mount seam introduction, semihosting consolidation, first-use format, flush-cache API change, path conventions, and validation results.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A tiny rabbit hops the seam so neat,
BKPTs hum, and FAT tables meet.
Mount, write, flush — the cache sings true,
Two vendors play while the pipeline grew.
Hooray for disks that boot and greet.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding PlusFAT-backed store to the FreeRTOS-Plus-TCP BDD target, which is the primary objective of this PR.
Description check ✅ Passed The description comprehensively covers Purpose, Change Description, Test Evidence, and Areas Affected sections. It explains the FS-mount seam, shared semihosting media, FFSemihostingDisk driver, target swap, durability fix, path changes, and documentation with specific test results and validation evidence.
Linked Issues check ✅ Passed The PR addresses all major objectives from issue #525: FS-mount seam with four function pointers [#525], per-target FS shims BddTargetFatFsMount and BddTargetPlusFatMount [#525], FFSemihostingDisk FF_Disk_t driver with mount-or-format-on-first-use [#525], shared semihosting SemihostingDisk TU [#525], PlusTCP target swap to PlusFAT with CMakeLists and FreeRTOSFATConfig.h [#525], ff_fflush defect fix to FF_FlushCache [#525], absolute store paths /STORE [#525], docs and DEVLOG [#525]. Test evidence confirms store BDD suite green on Plus-TCP, link checks pass, and lwIP target unchanged.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #525 scope: FS-mount seam, semihosting DRY, FFSemihostingDisk driver, target swap, durability fix, absolute paths, and docs. No unrelated refactoring, additional vendors, heap changes, or new transport features introduced beyond the stated scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/s29-05-plusfat-media-driver

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1428 passed)
   🚦   build-freertos-host-tdd-plustcp: 100% successful (✔️ 1773 passed)
   🚦   build-linux-clang: 100% successful (✔️ 1362 passed)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1362 passed)
   🚦   integration-linux-openssl: 100% successful (✔️ 16 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 14 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 16 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 48 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 88% successful (✔️ 45 passed, 🙈 6 skipped)
   🚦   bdd-freertos-qemu-plustcp: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   bdd-freertos-qemu-lwip: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1217 passed)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1362 passed)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
Bdd/Targets/Common/FFSemihostingDisk.c (1)

145-151: ⚡ Quick win

Extract disk validation expression into a static inline predicate.

The same 3-part composite condition is duplicated in both callbacks; a named predicate clarifies intent and keeps both paths in sync.

💡 Proposed refactor
 static int32_t ReadBlocks(uint8_t* buffer, uint32_t sector, uint32_t count, FF_Disk_t* disk);
 static int32_t WriteBlocks(uint8_t* buffer, uint32_t sector, uint32_t count, FF_Disk_t* disk);
 static FF_Error_t PartitionAndFormat(void);
+static inline bool FFSemihostingDisk_IsInvalidDisk(const FF_Disk_t* disk);
+
+static inline bool FFSemihostingDisk_IsInvalidDisk(const FF_Disk_t* disk)
+{
+    return (disk == NULL) || (disk->ulSignature != DISK_SIGNATURE) || (disk->xStatus.bIsInitialised == pdFALSE);
+}
@@
-    if ((disk == NULL) || (disk->ulSignature != DISK_SIGNATURE) || (disk->xStatus.bIsInitialised == pdFALSE))
+    if (FFSemihostingDisk_IsInvalidDisk(disk))
@@
-    if ((disk == NULL) || (disk->ulSignature != DISK_SIGNATURE) || (disk->xStatus.bIsInitialised == pdFALSE))
+    if (FFSemihostingDisk_IsInvalidDisk(disk))

As per coding guidelines: “Extract composite boolean conditions into intent-naming static inline predicates ... rather than inlining them into if/return.”

Also applies to: 170-176

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Bdd/Targets/Common/FFSemihostingDisk.c` around lines 145 - 151, Extract the
duplicated 3-part disk validation into a single static inline predicate (e.g.,
static inline BaseType_t DiskIsInvalid(const FF_Disk_t* disk) or DiskIsValid)
and use it from ReadBlocks and the corresponding write callback (the function
that contains the same check at 170-176) instead of repeating the composite if
expression; implement the predicate to check for NULL, ulSignature !=
DISK_SIGNATURE and xStatus.bIsInitialised == pdFALSE (returning true for invalid
or false for valid depending on your naming) and replace the original composite
condition in ReadBlocks and the other callback with a call to that predicate to
keep intent clear and both paths consistent.
Bdd/Targets/Common/diskio.c (1)

38-44: ⚡ Quick win

Extract repeated readiness check into a named predicate.

The same composite readiness condition is inlined in both read and write paths; a small predicate keeps intent explicit and removes duplication.

💡 Proposed refactor
 `#include` "SemihostingDisk.h"
+#include <stdbool.h>
+
+static inline bool Diskio_IsNotReady(BYTE pdrv)
+{
+    return (pdrv != 0) || (!SemihostingDisk_IsReady());
+}
@@
-    if ((pdrv != 0) || !SemihostingDisk_IsReady())
+    if (Diskio_IsNotReady(pdrv))
@@
-    if ((pdrv != 0) || !SemihostingDisk_IsReady())
+    if (Diskio_IsNotReady(pdrv))

As per coding guidelines: “Extract composite boolean conditions into intent-naming static inline predicates ... rather than inlining them into if/return.”

Also applies to: 63-69

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Bdd/Targets/Common/diskio.c` around lines 38 - 44, Extract the repeated
composite readiness check ((pdrv != 0) || !SemihostingDisk_IsReady()) used in
disk_read and the corresponding check in disk_write into a clearly named static
inline predicate (e.g., static inline bool SemihostingDisk_NotReady(BYTE pdrv)
or SemihostingDisk_IsInvalidDriveOrNotReady) and replace the inlined
conditionals with calls to that predicate; update both disk_read and disk_write
to use the new predicate so intent is explicit and duplication is removed while
keeping existing return values (RES_NOTRDY) and behavior intact.
Bdd/Targets/Common/SemihostingDisk.c (1)

40-47: ⚡ Quick win

Move helper definitions directly below first use.

The semihosting helper definitions are grouped at the file end instead of being placed immediately beneath their first caller.

As per coding guidelines: “Functions in source files ordered top-down ... helpers forward-declared at top and defined immediately beneath first caller”.

Also applies to: 153-222

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Bdd/Targets/Common/SemihostingDisk.c` around lines 40 - 47, The helper
functions (Semihosting, SemihostingOpen, SemihostingRead, SemihostingWrite,
SemihostingSeek, SemihostingFlen, SemihostingClose) are forward-declared at the
top but defined at the end of the file; move each helper's full definition to
immediately follow the first caller (i.e., place the Semihosting* function
implementations directly beneath the function that uses them first) and remove
unnecessary forward declarations so the file follows the top-down ordering
guideline and helpers appear right after their first use.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Bdd/Targets/Common/SemihostingDisk.c`:
- Around line 95-105: The current range check in SemihostingDisk_Read (and the
analogous check in SemihostingDisk_Write) can overflow because sector + count is
computed in 32-bit and may wrap; change the check to compute the sum in a wider
type or use a subtraction-based test to avoid wrap: either cast to uint64_t and
do uint64_t end = (uint64_t)sector + (uint64_t)count; if (end >
(uint64_t)SEMIHOSTING_DISK_SECTOR_COUNT) return SEMIHOSTING_DISK_OUT_OF_RANGE;
or use the safe check if (count != 0 && sector >
(uint32_t)(SEMIHOSTING_DISK_SECTOR_COUNT - count)) return
SEMIHOSTING_DISK_OUT_OF_RANGE; apply the same change inside
SemihostingDisk_Write to fix both bounds checks.

In `@docs/integrating-plusfat.md`:
- Line 17: The fenced code block containing "SolidSyslogBlockStore",
"SolidSyslogFileBlockDevice", and "your FF_Disk_t media driver" needs a language
label to satisfy markdownlint MD040; update the unlabeled triple-backtick fence
to include a language token (e.g., use "text") so the block becomes ```text
before the lines and the closing ``` remains unchanged; locate the block by
searching for the lines "SolidSyslogBlockStore" or "SolidSyslogFileBlockDevice"
and add the language label.

In `@Platform/PlusFat/Source/SolidSyslogPlusFatFile.c`:
- Line 101: Extract the composite return condition into a clearly named static
inline predicate, e.g. IsWriteFlushed(...), instead of returning wroteAll &&
(FF_FlushCache(self->Fp->pxIOManager) == FF_ERR_NONE) inline; add a file-scoped
static inline function that takes the same context needed (the current self
pointer and the wroteAll boolean), calls FF_FlushCache(self->Fp->pxIOManager)
and returns a bool comparing to FF_ERR_NONE combined with wroteAll, then replace
the original return expression with a call to that predicate to make the intent
self-documenting.

---

Nitpick comments:
In `@Bdd/Targets/Common/diskio.c`:
- Around line 38-44: Extract the repeated composite readiness check ((pdrv != 0)
|| !SemihostingDisk_IsReady()) used in disk_read and the corresponding check in
disk_write into a clearly named static inline predicate (e.g., static inline
bool SemihostingDisk_NotReady(BYTE pdrv) or
SemihostingDisk_IsInvalidDriveOrNotReady) and replace the inlined conditionals
with calls to that predicate; update both disk_read and disk_write to use the
new predicate so intent is explicit and duplication is removed while keeping
existing return values (RES_NOTRDY) and behavior intact.

In `@Bdd/Targets/Common/FFSemihostingDisk.c`:
- Around line 145-151: Extract the duplicated 3-part disk validation into a
single static inline predicate (e.g., static inline BaseType_t
DiskIsInvalid(const FF_Disk_t* disk) or DiskIsValid) and use it from ReadBlocks
and the corresponding write callback (the function that contains the same check
at 170-176) instead of repeating the composite if expression; implement the
predicate to check for NULL, ulSignature != DISK_SIGNATURE and
xStatus.bIsInitialised == pdFALSE (returning true for invalid or false for valid
depending on your naming) and replace the original composite condition in
ReadBlocks and the other callback with a call to that predicate to keep intent
clear and both paths consistent.

In `@Bdd/Targets/Common/SemihostingDisk.c`:
- Around line 40-47: The helper functions (Semihosting, SemihostingOpen,
SemihostingRead, SemihostingWrite, SemihostingSeek, SemihostingFlen,
SemihostingClose) are forward-declared at the top but defined at the end of the
file; move each helper's full definition to immediately follow the first caller
(i.e., place the Semihosting* function implementations directly beneath the
function that uses them first) and remove unnecessary forward declarations so
the file follows the top-down ordering guideline and helpers appear right after
their first use.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 861f4d4c-c256-4205-af4e-edb8c0403905

📥 Commits

Reviewing files that changed from the base of the PR and between 21e0a82 and d921442.

📒 Files selected for processing (23)
  • Bdd/Targets/Common/BddTargetFatFsMount.c
  • Bdd/Targets/Common/BddTargetFatFsMount.h
  • Bdd/Targets/Common/BddTargetFreeRtosPipeline.c
  • Bdd/Targets/Common/BddTargetFreeRtosPipeline.h
  • Bdd/Targets/Common/BddTargetPlusFatMount.c
  • Bdd/Targets/Common/BddTargetPlusFatMount.h
  • Bdd/Targets/Common/FFSemihostingDisk.c
  • Bdd/Targets/Common/FFSemihostingDisk.h
  • Bdd/Targets/Common/SemihostingDisk.c
  • Bdd/Targets/Common/SemihostingDisk.h
  • Bdd/Targets/Common/diskio.c
  • Bdd/Targets/FreeRtos/CMakeLists.txt
  • Bdd/Targets/FreeRtos/FreeRTOSConfig.h
  • Bdd/Targets/FreeRtos/FreeRTOSFATConfig.h
  • Bdd/Targets/FreeRtos/main.c
  • Bdd/Targets/FreeRtosLwip/CMakeLists.txt
  • Bdd/Targets/FreeRtosLwip/main.c
  • DEVLOG.md
  • Platform/PlusFat/Source/SolidSyslogPlusFatFile.c
  • Tests/PlusFat/SolidSyslogPlusFatFileTest.cpp
  • Tests/Support/PlusFatFakes/Interface/PlusFatFake.h
  • Tests/Support/PlusFatFakes/Source/PlusFatFake.c
  • docs/integrating-plusfat.md

Comment thread Bdd/Targets/Common/SemihostingDisk.c Outdated
Comment thread docs/integrating-plusfat.md Outdated
Comment thread Platform/PlusFat/Source/SolidSyslogPlusFatFile.c Outdated
CodeRabbit + review feedback on the S29.05 sources (no behaviour change):

- SemihostingDisk.c: overflow-safe SemihostingDisk_IsRangeValid (subtraction
  form, no sector+count wrap), shared by Read/Write; reorder the Semihosting*
  primitives beneath their first callers (top-down reading).
- FFSemihostingDisk.c: extract the duplicated disk-validation check into
  FFSemihostingDisk_IsValidDisk.
- diskio.c: extract the readiness check into Diskio_IsDriveReady.
- SolidSyslogPlusFatFile.c: reorder so Close sits beneath its first caller
  (Cleanup); add PlusFatFile_IsFileOpen used at every open-state site; extract
  the write durability flush into PlusFatFile_Flush (honest action verb;
  parenthesise the wroteAll equality).
- docs/integrating-plusfat.md: label the architecture fence 'text' (MD040).

Verified: clang-format clean tree-wide; host SolidSyslogPlusFatFileTest 30/30;
both FreeRTOS cross targets build.
@DavidCozens

Copy link
Copy Markdown
Owner Author

Thanks for the review — all six addressed in 4e3d8f8 (no behaviour change; clang-format clean tree-wide, host SolidSyslogPlusFatFileTest 30/30, both FreeRTOS cross targets build):

  • SemihostingDisk.c (overflow in range check) — fixed via SemihostingDisk_IsRangeValid(sector, count) using the subtraction form sector <= COUNT - count (no sector + count wrap), shared by Read and Write. Note: practically unreachable given the only callers are FatFs disk_* / Plus-FAT FF_BlockRead/Write on a 16384-sector disk, but it's a cheap hardening of an existing guard.
  • SemihostingDisk.c (helper ordering) — the Semihosting* primitives now sit beneath their first callers for top-down reading.
  • diskio.c (readiness predicate) — extracted Diskio_IsDriveReady(pdrv); both paths use if (!Diskio_IsDriveReady(pdrv)).
  • FFSemihostingDisk.c (disk-validation predicate) — extracted FFSemihostingDisk_IsValidDisk(disk); both block callbacks use it.
  • SolidSyslogPlusFatFile.c (write/flush predicate) — extracted, then refined during review: the helper performs the flush, so it's named as an honest action PlusFatFile_Flush(self) (returns success) rather than an Is… predicate. Also reordered so Close sits beneath its first caller (Cleanup) and added PlusFatFile_IsFileOpen used at every open-state site.
  • docs/integrating-plusfat.md (MD040) — fenced the architecture diagram as text.

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1428 passed)
   🚦   build-freertos-host-tdd-plustcp: 100% successful (✔️ 1773 passed)
   🚦   build-linux-clang: 100% successful (✔️ 1362 passed)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1362 passed)
   🚦   integration-linux-openssl: 100% successful (✔️ 16 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 14 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 16 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 48 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 88% successful (✔️ 45 passed, 🙈 6 skipped)
   🚦   bdd-freertos-qemu-plustcp: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   bdd-freertos-qemu-lwip: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1217 passed)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1362 passed)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

The intent-named-predicate reorder shifted SolidSyslogPlusFatFile.c's
SelfFromBase cast from line 45 to 47, leaving the misra-c2012-11.3 suppression
stale and the (deviated) cast unsuppressed — failing analyze-cppcheck. Point the
suppression at the new line. cppcheck-misra clean on Platform/PlusFat again.
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1428 passed)
   🚦   build-freertos-host-tdd-plustcp: 100% successful (✔️ 1773 passed)
   🚦   build-linux-clang: 100% successful (✔️ 1362 passed)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1362 passed)
   🚦   integration-linux-openssl: 100% successful (✔️ 16 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 14 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 16 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 48 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 88% successful (✔️ 45 passed, 🙈 6 skipped)
   🚦   bdd-freertos-qemu-plustcp: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   bdd-freertos-qemu-lwip: 86% successful (✔️ 44 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1217 passed)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1362 passed)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit 0d013d1 into main Jun 4, 2026
27 checks passed
@DavidCozens DavidCozens deleted the feat/s29-05-plusfat-media-driver branch June 4, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S29.05: PlusFAT FF_Disk_t semihosting media driver + swap PlusTCP target FatFs→PlusFAT; store BDD green; docs/integrating-plusfat.md

1 participant