feat: S28.09 FreeRtosLwip LAN9118 netif + NO_SYS=0 UDP on QEMU#476
Conversation
Grow the S28.07 link-probe into a runnable FreeRTOS+lwIP BDD target on QEMU mps2-an385: a hand-written LAN9118 lwIP netif (netif/EthernetIf.c) over the vendored Arm smsc9220 driver (Apache-2.0), tcpip_init + static IP bring-up on the tcpip thread, and the SolidSyslog UDP pipeline wired through the tcpip_callback marshal (S28.06). Verified on QEMU: boot, ARP, and a correct RFC 5424 datagram to 10.0.2.2:5514, clean teardown, no PlusTcp symbols. WIP: oracle BDD run + CI lanes still to come. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the syslog-ng-freertos-lwip / behave-freertos-lwip compose pair (mirrors the +TCP pair, points at the lwIP ELF, UDP-only tag filter with a @freertoslwipwip escape hatch) and the advisory bdd-freertos-qemu-lwip CI job (not in summary.needs). Grow build-freertos-target-lwip to upload the BDD tunables mirror; refresh the link-probe wording to BDD target across ci.yml, the top-level CMake status, and the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rmat The LwipRaw datagram sends PBUF_REF packets pointing at a transient buffer, so a first send that hit an ARP miss had its queued copy reference freed memory and was dropped (confirmed on the wire: seqId=1 lost, seqId=2 delivered). Warm up the gateway ARP at bring-up (etharp_request) and block the interactive task — never the tcpip thread — until the cache populates before the pipeline goes live. Verified: both seqId=1 and seqId=2 now reach the wire. Also move the vendored Arm smsc9220 driver into netif/smsc9220/ behind a DisableFormat .clang-format so the analyze-format lane does not reflow third-party code, and clang-format the hand-written netif / main / config files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThis PR converts the FreeRTOS+lwIP BDD target from a CI-only link‑probe into a runnable NO_SYS=0 QEMU target: adds a vendored LAN9118 driver, lwIP netif wrapper, expanded FreeRTOS/lwIP threading config, a SolidSyslog interactive BDD runtime with ARP warm‑up, CMake wiring, CI lane, and docs/DEVLOG entries. ChangesFreeRTOS+lwIP BDD Target
Sequence DiagramsequenceDiagram
participant Developer
participant CI
participant QEMU as FreeRTOS/QEMU target
participant lwIP as tcpip thread
participant Driver as SMSC9220 driver
participant Oracle as syslog-ng
Developer->>CI: push PR (build & artifacts)
CI->>QEMU: upload/download ELF & tunables
CI->>Oracle: start syslog-ng-freertos-lwip
CI->>QEMU: start behave-freertos-lwip (runs tests)
QEMU->>lwIP: tcpip_init, netif_add, ARP warm-up
lwIP->>Driver: linkoutput/send_by_chunks (TX)
Driver->>Oracle: network packets delivered to syslog-ng
Oracle->>CI: test results (JUnit)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
☀️ Quality Summary 🚦 build-linux-gcc: 100% successful (✔️ 1344 passed) Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result. |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (1)
Bdd/Targets/FreeRtosLwip/netif/EthernetIf.c (1)
227-230: ⚡ Quick winPrefer
smsc9220_get_interrupt()over the localextern get_irq_status()inEthernetISR.
smsc9220_eth_drv.hexposesint smsc9220_get_interrupt(dev, source), which returnsGET_BIT(register_map->irq_status, source); since the ISR already usesSMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL, replace theget_irq_status(dev) & rxFifoStatusBitcheck withsmsc9220_get_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL) != 0and drop the localexternto avoid coupling to the internal symbol.🤖 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/FreeRtosLwip/netif/EthernetIf.c` around lines 227 - 230, In EthernetISR replace the use of the local extern get_irq_status(dev) check with the public API: call smsc9220_get_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL) and test it != 0, and remove the local extern uint32_t get_irq_status(...) declaration; this keeps the ISR using the driver-exported smsc9220_get_interrupt function and avoids coupling to the internal get_irq_status symbol.
🤖 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 @.github/workflows/ci.yml:
- Around line 1157-1158: The workflow uses the mutable reference
dorny/test-reporter@v3 (e.g., the step named "BDD Test Report (FreeRTOS+lwIP)")
which should be pinned to a specific commit SHA; update every occurrence of
dorny/test-reporter@v3 in the CI workflow to the full commit SHA (the same
pattern used for other actions) so the action reference is immutable and
reproducible.
- Line 1133: The checkout step in the bdd-freertos-qemu-lwip job is leaving Git
credentials inside the workspace that get bind-mounted into containers; update
the actions/checkout@... step (the checkout action invocation) to include
persist-credentials: false so credentials are not written into the checked-out
.git directory before the docker compose step mounts the repo.
In `@Bdd/Targets/FreeRtosLwip/main.c`:
- Around line 567-587: TeardownAll uses a fixed 20ms vTaskDelay to hope
ServiceTask sees solidSyslogTeardown before lifecycleMutex is destroyed; instead
ensure the service has actually exited (or been signalled to exit) before
destroying lifecycleMutex. Modify TeardownAll to set solidSyslogTeardown, then
notify the service task (e.g., xTaskNotify or give a semaphore) and block
waiting for a confirmation from the service (e.g., service clears
serviceTaskHandle or gives a "terminated" semaphore/task notification) or poll
serviceTaskHandle in a loop with vTaskDelay and a sensible timeout; only after
receiving the explicit confirmation that ServiceTask has finished should you
call SolidSyslogFreeRtosMutex_Destroy(lifecycleMutex). Use the existing symbols
solidSyslogTeardown, serviceTaskHandle, lifecycleMutex and TeardownAll to
implement this handshake.
- Around line 368-370: When updating the "host" via TryUpdateString(host,
sizeof(host), value) in main.c, also increment the endpointVersion so
GetEndpointVersion() changes and the new host takes effect immediately; modify
the branch handling strcmp(name, "host") to detect a successful update
(TryUpdateString returned true) and bump endpointVersion (the variable used by
GetEndpointVersion()) after the update, similar to how port changes trigger the
version bump.
- Around line 204-206: Check the return values from both xTaskCreate calls (the
InteractiveTask and ServiceTask creations) instead of ignoring them; if either
returns an error (not pdPASS) log/report the failure and avoid calling
vTaskStartScheduler (e.g., return or loop/error-handle), and ensure
serviceTaskHandle is only used if ServiceTask creation succeeded. Update the
xTaskCreate calls in main (InteractiveTask, ServiceTask,
SERVICE_TASK_STACK_DEPTH, INTERACTIVE_TASK_STACK_DEPTH, and serviceTaskHandle)
to capture and check their return values and handle a failed creation path
before vTaskStartScheduler is invoked.
- Around line 256-282: The code incorrectly uses tcpip_callback which only
queues work; change both WarmUpGatewayArp and LwipTcpipMarshal to use
tcpip_callback_wait (or an equivalent completion API) so the caller blocks until
the posted callback finishes; in WarmUpGatewayArp ensure the boolean resolved is
safe to pass (stack-to-callback race) by either allocating a stable completion
object or using tcpip_callback_wait so the callback writes to resolved before
the function reads it; replace tcpip_callback(callback, context) calls in
LwipTcpipMarshal and the WarmUpGatewayArp loop with tcpip_callback_wait to
guarantee synchronous behavior.
In `@Bdd/Targets/FreeRtosLwip/netif/EthernetIf.c`:
- Around line 197-219: EthernetIf_LowLevelInput currently returns NULL for
overlength frames and leaves the RX FIFO intact; change it so that when
smsc9220_peek_next_packet_size() returns length > sizeof(EthernetIf_RxBuffer)
you explicitly drain that frame by calling smsc9220_receive_by_chunks() (into a
temporary discard buffer or in chunks) and update stats (e.g.,
LINK_STATS_INC(link.drop) and LINK_STATS_INC(link.memerr) as appropriate) before
returning NULL; keep the normal path for valid lengths that allocate a pbuf, and
ensure this drain behavior mirrors what
empty_rx_fifo()/smsc9220_receive_by_chunks() expect so the RX FIFO level
interrupt can deassert.
In `@Bdd/Targets/FreeRtosLwip/netif/smsc9220/smsc9220_eth_drv.c`:
- Around line 319-336: The code is prepending a pad DWORD even when the chunk is
already 4-byte aligned; change the logic so when remainder_bytes == 0 you do not
build or write a leading padded word. Specifically, in the block that computes
remainder_bytes and filler_bytes and fills tx_data_port_tmp_ptr (using
remainder_bytes, filler_bytes, tx_data_port_tmp_ptr, tx_data_port_tmp,
register_map->tx_data_port, size_bytes and data), skip the padding loop and the
write to register_map->tx_data_port for aligned chunks — only write actual data
words directly when remainder_bytes == 0; when remainder_bytes != 0 keep the
existing filler loop but only subtract remainder_bytes from size_bytes and
advance data when you actually consumed those start bytes. Also apply the same
fix at the other location that uses current_size % 4 (the 1150-1155 block) so
aligned segments are not prepended with a dummy DWORD.
- Around line 455-468: The busy-bit poll in smsc9220_mac_regwrite is incorrectly
masking register_map->mac_csr_cmd with the boolean result of GET_BIT, causing
the loop to test bit 0 instead of the BUSY bit; update the loop condition to
directly test the BUSY bit (either by using GET_BIT(register_map->mac_csr_cmd,
MAC_CSR_CMD_BUSY_INDEX) as the boolean expression or by masking
register_map->mac_csr_cmd with (1u << MAC_CSR_CMD_BUSY_INDEX)) so the loop only
exits when the BUSY bit is cleared or time_out reaches zero; change the
condition in the do/while to use one of these correct checks and keep the rest
of the smsc9220_mac_regwrite logic intact.
- Around line 855-859: smsc9220_check_id currently returns 0/1 causing callers
(like smsc9220_init) to interpret failure as SMSC9220_ERROR_TIMEOUT; change its
return to the proper smsc9220_error_t values: check the chip ID using
GET_BIT_FIELD(id, CHIP_ID_MASK, CHIP_ID_POS) == CHIP_ID and return the success
enum (e.g., SMSC9220_ERROR_NONE or SMSC9220_OK) on match and a specific chip-id
error enum (e.g., SMSC9220_ERROR_CHIP_ID or SMSC9220_ERROR_ID_MISMATCH) on
mismatch so callers receive the correct error code. Ensure the function
signature remains int -> smsc9220_error_t (or update signature to
smsc9220_error_t) and update any callers if you change the return type.
In `@Bdd/Targets/FreeRtosLwip/README.md`:
- Around line 27-29: The README references incorrect vendored driver
paths—update the mention of `netif/smsc9220_eth_drv.{c,h}` and
`netif/smsc9220_emac_config.h` to reflect the actual directory layout under
`netif/smsc9220/` (for example, `netif/smsc9220/smsc9220_eth_drv.c`,
`netif/smsc9220/smsc9220_eth_drv.h`, and
`netif/smsc9220/smsc9220_emac_config.h`) so the documented paths match the
repository structure in README.md.
In `@DEVLOG.md`:
- Around line 12986-12993: Update the DEVLOG wording to avoid implying an lwIP
API called tcpip_callback_with_block: explain that the adapters use the blocking
marshal wrapper implemented by LwipTcpipMarshal (installed via
SolidSyslogLwipRaw_SetMarshal), and that LwipTcpipMarshal internally calls the
lwIP API tcpip_callback(...) to achieve the synchronous/blocking behavior;
either rename the informal “tcpip_callback_with_block” to “LwipTcpipMarshal
(tcpip_callback-based blocking marshal)” or add an explicit mapping sentence
linking the informal term to the LwipTcpipMarshal implementation and its use of
tcpip_callback.
---
Nitpick comments:
In `@Bdd/Targets/FreeRtosLwip/netif/EthernetIf.c`:
- Around line 227-230: In EthernetISR replace the use of the local extern
get_irq_status(dev) check with the public API: call smsc9220_get_interrupt(dev,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL) and test it != 0, and remove the local
extern uint32_t get_irq_status(...) declaration; this keeps the ISR using the
driver-exported smsc9220_get_interrupt function and avoids coupling to the
internal get_irq_status symbol.
🪄 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: 40028f94-5c5b-479d-b55a-cbaaaddb1333
📒 Files selected for processing (17)
.github/workflows/ci.ymlBdd/Targets/FreeRtosLwip/CMakeLists.txtBdd/Targets/FreeRtosLwip/FreeRTOSConfig.hBdd/Targets/FreeRtosLwip/README.mdBdd/Targets/FreeRtosLwip/lwipopts.hBdd/Targets/FreeRtosLwip/main.cBdd/Targets/FreeRtosLwip/netif/EthernetIf.cBdd/Targets/FreeRtosLwip/netif/EthernetIf.hBdd/Targets/FreeRtosLwip/netif/smsc9220/.clang-formatBdd/Targets/FreeRtosLwip/netif/smsc9220/smsc9220_emac_config.hBdd/Targets/FreeRtosLwip/netif/smsc9220/smsc9220_eth_drv.cBdd/Targets/FreeRtosLwip/netif/smsc9220/smsc9220_eth_drv.hBdd/Targets/FreeRtosLwip/solidsyslog_user_tunables.hCMakeLists.txtCMakePresets.jsonDEVLOG.mdci/docker-compose.bdd.yml
…sion, RX drain Apply the actionable, in-scope findings from the CodeRabbit review of #476, matching the established Bdd/Targets/FreeRtos (+TCP) sibling where it diverged: - main.c: check both xTaskCreate results and SemihostingExit(1) on failure rather than entering vTaskStartScheduler with a missing task (sibling does the same guard). - main.c: bump endpointVersion when `set host` changes the host, so a host change takes effect without also changing port (sibling already does this). - main.c: correct the LwipTcpipMarshal comment — tcpip_callback only blocks until the work is queued; synchronicity here comes from TCPIP_THREAD_PRIO being above every marshalling task. Records the LOCK_TCPIP_CORE follow-up. - EthernetIf.c: drain an oversize/corrupt RX frame from the FIFO in word-aligned chunks instead of returning NULL, which would re-peek the same frame forever and wedge receive. - README.md / DEVLOG.md: fix the vendored driver paths (netif/smsc9220/) and the tcpip_callback wording. Oracle re-run green (8 features / 25 scenarios / 96 steps, 0 failed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #476 review #4. tcpip_callback only blocks until the work is queued, so LwipTcpipMarshal previously relied on TCPIP_THREAD_PRIO preempting every marshalling task to appear synchronous — a correct-but-implicit invariant. LWIP_TCPIP_CORE_LOCKING is enabled, so run the callback in the caller's task context under a LOCK_TCPIP_CORE/UNLOCK_TCPIP_CORE pair instead: unconditionally synchronous regardless of priority, with no per-send mailbox message. The ARP warm-up query reuses the same marshal, which also closes the stack-`resolved` race in WarmUpGatewayArp. NetworkBringUp stays on tcpip_callback (its smsc9220_init calls vTaskDelay and must not run under the held core lock). Oracle re-run green (8 features / 25 scenarios / 96 steps, 0 failed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeRabbit review triageThanks @coderabbitai. Verified all 12 findings against the code and the merged Fixed in this PR
Oracle re-run green after each change: 8 features / 25 scenarios / 96 steps, 0 failed. Deferred (tracked, not dropped)
S28.09 stays UDP-scoped; the deferrals are real-hardware / project-wide hygiene that belong outside this story. |
|
A few notes on the fixes:
The deferrals are sensibly scoped: All findings are either fixed or tracked — happy to resolve all outstanding review comments on this PR if you'd like. 🐇 ✓ ✏️ Learnings added
✅ Actions performedComments resolved. Approval is disabled; enable |
☀️ Quality Summary 🚦 build-linux-gcc: 100% successful (✔️ 1344 passed) Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result. |
Adds `persist-credentials: false` to all 26 `actions/checkout` steps (25 in ci.yml, 1 in sbom.yml) so the checkout's GITHUB_TOKEN is not persisted in .git/config for later steps — the BDD compose lanes bind-mount the repo root into containers. Closes the zizmor `artipacked` finding deferred from #476. SHA-pins the three remaining tag-pinned actions so the workflow tree is zizmor `unpinned-uses`-clean: - dorny/test-reporter@v3 -> a43b3a5 # v3.0.0 - actions/cache@v4 -> (then bumped to v5, see below) - uhafner/quality-monitor@v1 -> 778e3a6 # v1.14.0 Sweeps the entire workflow tree (ci.yml, sbom.yml, release-please.yml) off the deprecated Node 20 runtime (forced off the runner from 2026-06-16) to the node24 release of each action: - actions/upload-artifact -> 043fb46 # v7.0.1 - actions/download-artifact -> 3e5f45b # v8.0.1 - actions/cache -> 27d5ce7 # v5.0.5 - actions/github-script -> ed59741 # v8.0.0 - actions/deploy-pages -> cd2ce8f # v5.0.0 - googleapis/release-please-action -> 45996ed # v5.0.0 Verified node24-clean: every pinned SHA's action.yml resolves to using:node24 (or composite/docker); no node20 and no unpinned uses remain. Behaviour notes (acceptable pre-release): download-artifact@v8 defaults a hash mismatch to a hard error; release-please-action@v5 marks node24 a breaking change but it is only the runtime bump. The deploy-pages and release-please lanes run on main only, so this PR's CI does not exercise them. Closes #477 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#485) Adds `persist-credentials: false` to all 26 `actions/checkout` steps (25 in ci.yml, 1 in sbom.yml) so the checkout's GITHUB_TOKEN is not persisted in .git/config for later steps — the BDD compose lanes bind-mount the repo root into containers. Closes the zizmor `artipacked` finding deferred from #476. SHA-pins the three remaining tag-pinned actions so the workflow tree is zizmor `unpinned-uses`-clean: - dorny/test-reporter@v3 -> a43b3a5 # v3.0.0 - actions/cache@v4 -> (then bumped to v5, see below) - uhafner/quality-monitor@v1 -> 778e3a6 # v1.14.0 Sweeps the entire workflow tree (ci.yml, sbom.yml, release-please.yml) off the deprecated Node 20 runtime (forced off the runner from 2026-06-16) to the node24 release of each action: - actions/upload-artifact -> 043fb46 # v7.0.1 - actions/download-artifact -> 3e5f45b # v8.0.1 - actions/cache -> 27d5ce7 # v5.0.5 - actions/github-script -> ed59741 # v8.0.0 - actions/deploy-pages -> cd2ce8f # v5.0.0 - googleapis/release-please-action -> 45996ed # v5.0.0 Verified node24-clean: every pinned SHA's action.yml resolves to using:node24 (or composite/docker); no node20 and no unpinned uses remain. Behaviour notes (acceptable pre-release): download-artifact@v8 defaults a hash mismatch to a hard error; release-please-action@v5 marks node24 a breaking change but it is only the runtime bump. The deploy-pages and release-please lanes run on main only, so this PR's CI does not exercise them. Closes #477 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Purpose
S28.09 (#472, epic E28) gives the
FreeRtosLwipBDD target a workingnetwork stack: a hand-written lwIP netif over Arm's smsc9220 LAN9118
driver, lwIP in
NO_SYS=0(tcpip-thread) mode, and a UDP loggingpipeline proven end-to-end against the syslog-ng oracle on QEMU.
Closes #472.
Change Description
Bdd/Targets/FreeRtosLwip/netif/smsc9220/(Apache-2.0 headers kept),isolated from
analyze-formatwith aDisableFormat.clang-format.Hand-written netif glue
netif/EthernetIf.c(RX task driven by IRQ-13EthernetISR, pbuf TX/RX,etharp_output).lwipopts.hruns the tcpip thread + contribsys_arch.c;FreeRTOSConfig.hmirrors the requirements; newsolidsyslog_user_tunables.h(MAX_MESSAGE_SIZE 512, FreeRtosMutex pool 2)flows in via the
freertos-cross-lwippreset.main.ccallstcpip_initpre-scheduler; netif bring-upruns from the interactive task via
tcpip_callback(smsc9220_init callsvTaskDelay, so it must run post-scheduler). lwIP-touching adapter opsare marshalled through a
tcpip_callback_with_blockshim installed withS28.06's
SolidSyslogLwipRaw_SetMarshal. UDP path = UdpSender +CircularBuffer + FreeRtosMutex + Service task + Meta/TimeQuality/Origin
SD. SwitchingSender TCP/TLS slots are wired to
NullSender(UDP onlythis story; TCP is S28.10).
LwipRawDatagramsends zero-copy(PBUF_REF over a transient buffer), so an ARP-miss first send had its
queued copy reference freed memory (seqId=1 lost, seqId=2 delivered).
Fix is
WarmUpGatewayArp:etharp_request(gw)at bring-up + polletharp_find_addr(marshalled off the tcpip thread) until resolvedbefore the pipeline goes live — keeps the zero-copy contract and pushes
the one-time resolution cost to setup. pcap now shows gratuitous ARP →
gw ARP request → reply → UDP seqId=1 → seqId=2 in order.
bdd-freertos-qemu-lwiplane +syslog-ng/behavecompose pair (UDP-only tag filter,
@freertoslwipwipper-scenarioescape hatch);
build-freertos-target-lwipuploads thebdd-tunables-freertos-lwipartifact. NOT insummary.needs—advisory until S28.11 promotes it.
Test Evidence
container):
docker compose -f ci/docker-compose.bdd.yml up --abort-on-container-exit --exit-code-from behave-freertos-lwip behave-freertos-lwip syslog-ng-freertos-lwip→ 8 features passed, 0 failed; 25 scenarios passed, 0 failed; 96 steps
passed, 0 failed (24 scenarios skipped — the TCP/TLS/mTLS/store
features excluded by the UDP-only tag filter). Delivery truth is the
syslog-ng oracle's "receives a message with priority/hostname/PROCID"
assertions, not an ad-hoc host listener (slirp does not reliably
deliver the NATed datagram to host loopback even though it is correct
on the wire).
arm-none-eabi-nmconfirmszero PlusTcp symbols linked into the lwIP ELF.
clang-format --dry-run --Werror(clang-format 19.1.7) clean.Areas Affected
Bdd/Targets/FreeRtosLwip/(Tier 3 best-effort BDD target) — new netif,driver, pipeline, tunables, presets.
.github/workflows/ci.yml,ci/docker-compose.bdd.yml— advisory lwIPlane + compose pair.
CMakeLists.txt/CMakePresets.json—freertos-cross-lwipwiring. No Tier-1/2 production source (
Core/,Platform/) touched.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
CI/Testing Improvements
Documentation