Integration: merge wingsail, rudder and pdb module branches into main - #62
Merged
Conversation
Signed-off-by: Michael Greenough <43833591+MichaelGreenough@users.noreply.github.com>
Signed-off-by: Michael Greenough <43833591+MichaelGreenough@users.noreply.github.com>
Signed-off-by: Michael Greenough <43833591+MichaelGreenough@users.noreply.github.com>
Signed-off-by: Michael Greenough <43833591+MichaelGreenough@users.noreply.github.com>
Signed-off-by: Michael Greenough <43833591+MichaelGreenough@users.noreply.github.com>
…tate of code functionality
Should work? unless I overlooked something or tested it wrong Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Signed-off-by: hml04 <160178026+hml04@users.noreply.github.com>
Signed-off-by: ELEC_lead-ubcsailbot <electrical@ubcsailbot.org>
Signed-off-by: ELEC_lead-ubcsailbot <electrical@ubcsailbot.org>
Signed-off-by: ELEC_lead-ubcsailbot <electrical@ubcsailbot.org>
Signed-off-by: ELEC_lead-ubcsailbot <electrical@ubcsailbot.org>
Signed-off-by: alisha1697 <143849351+alisha1697@users.noreply.github.com>
Added how to power the encoder on the PCB and adjusted a couple of settings in order to get the encoder working, Signed-off-by: JoshuaO956 <148372526+JoshuaO956@users.noreply.github.com>
…ule-firmware into rudder-working-branch
…dditional Buffers in NMEA0183
Bring in generic rudder param tuning (#56) and the CANFD heartbeat. Conflicts resolved toward the IMU branch's control model: kept the real irons() and the RudderSM_Update state machine over the working branch's return-0 stub, and adopted the param-tuning CAN IDs (PID coeffs 0x200, generic params 0x210). Pin the PLRS-IMU submodule to main (now ae4b540). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- getBinaryBits() accumulated raw AIS chars into a uint32_t before masking - Fields spanning 6 chars (36 bits) overflowed it, including MMSI (bits 8-37) and longitude for message types 18/19 - Overflow silently dropped bits the final mask still needed - Result: MMSI top bits zeroed (316xxxxxx read as 047xxxxxx), lat/lon corrupted - Fix: widen accumulator to uint64_t, truncate to uint32_t only after masking
The CV7 sends MWV (wind angle/speed) and XDR (temperature) back-to-back each cycle. The scheduler was calling WIND_SENSOR__CAN_transmit for both, causing 0x040 to be sent twice per cycle — the XDR-triggered transmission sent stale wind data since XDR only updates temp, which isn't in 0x040.
The link pointed at an absolute path in a specific contributor's home
directory, so CubeIDE dropped the folder on every other machine. The
generated makefile then had no briter-encoders entry and the build failed
with "BRITER.h: No such file or directory".
Use the same ${PARENT-2-PROJECT_LOC} form as CANFD, MDB961WP and nmea0183.
Rudder control model, state machine and PLRS-IMU integration.
Power distribution board controller and CAN heartbeat.
Resolves the three-way divergence between the module branches. Conflicts were resolved by ownership: each controller project goes to the branch that develops it, shared modules go to the version that is safe to share. firmware/com-modules/CANFD/can.c -> rudder Only rudder's copy keeps __weak on HAL_FDCAN_RxFifo0Callback and HAL_TIM_PeriodElapsedCallback, which a controller project must be able to override without a duplicate-symbol link error. It is also the only copy that counts a heartbeat TX failure instead of calling Error_Handler(), which on the bench (no CAN ACK) would fault the board every 10s. library-test-project can.h / can.c -> wingsail Rudder's committed copies contain unresolved conflict markers (2 in can.h, 12 in can.c). Wingsail's are clean. wingsail-controller/*, drv-modules/nmea0183/* -> wingsail rudder-controller/.cproject, BNO055-imu, motor-base-PID -> rudder firmware/PLRS-IMU -> rudder (e01ef3b) Wingsail carried a gitlink with no .gitmodules at all, so the submodule was unusable from a fresh clone. Rudder ships a valid .gitmodules and a newer commit, and wingsail does not reference PLRS-IMU. .gitignore -> union of both sides stm32u5xx_hal_tim.c / _tim_ex.c -> clean vendored copies (rename collision)
This was referenced Aug 16, 2026
First CI in this repo. Two jobs on every PR. ioc-sync compares each .ioc's declared peripherals (Mcu.IPn) against the MX_<PERIPH>_Init functions in the generated Core/Src/main.c. The dangerous direction is an init present in main.c but absent from the .ioc: it sits outside the USER CODE guards, so the next CubeMX regeneration deletes it silently. This runs on a plain checkout with no CubeMX installed. It does not verify pin assignments or clock trees; only CubeMX can do that. A full regenerate-and-diff is impractical here anyway, because the six projects were generated by five different CubeMX versions (6.10.0 through 6.16.1), so a single CI version would produce spurious diffs everywhere. One real drift exists today and is recorded in tools/ioc-sync-ignore.txt: library-test-project hand-writes MX_I2C3_Init and MX_I2C4_Init while its .ioc declares only I2C1/I2C2. Documented rather than hidden, so CI stays actionable. host-tests builds the drv-modules against the stub HAL with plain gcc and runs the five working suites. canfd_test is excluded because it does not compile: the stubs lack TIM_HandleTypeDef, HAL_TIM_Base_Start_IT, FDCAN_IT_DATA_PROTOCOL_ERROR, FDCAN_IT_ARB_PROTOCOL_ERROR and __weak. That breakage predates this branch (it fails on wingsail-working-branch too).
canfd_test never compiled, so the CANFD module, the one piece of code shared by
all three controllers, had no test coverage in CI. The stub HAL was missing
everything can.c touches outside FDCAN transmit/receive.
Added to stubs/stm32u5xx_hal.h:
- __weak, expanding to nothing on host (target gets it from CMSIS)
- TIM_TypeDef, TIM_HandleTypeDef and HAL_TIM_Base_Start_IT
- TIM7 as a memory-mapped address, mirroring CMSIS, so the
htim->Instance == TIM7 comparison works with no linker symbol
Added to stubs/stm32u5xx_hal_fdcan.h the five bus-error notification bits
CAN_Init activates: ERROR_WARNING, ERROR_PASSIVE, BUS_OFF, ARB_PROTOCOL_ERROR
and DATA_PROTOCOL_ERROR.
canfd_test.c now defines hfdcan1 and htim7, which CubeMX generates into main.c
on target and can.c references as extern.
All six suites now pass under -Werror, so CI runs `make -C tests test` directly
instead of an allowlist of the ones that happened to build.
Standardises on 6.15.0: three of six projects are already there
(FDCAN_Library_CB, pdb-controller, rudder-controller), all on STM32Cube
FW_U5 V1.8.0.
Running CubeMX itself in CI is not viable and this check exists instead.
CubeMX raises a modal migrate/continue/cancel dialog whenever a project's
version differs from the installed one, and it does so even in -q script mode
on a headless machine, so the run just blocks. It also needs a ~1GB unfree
download and a license click-through. A static check gives the guarantee that
matters (nobody silently changes the generator version) at no runtime cost.
Three projects cannot move yet and are recorded in
tools/ioc-version-exceptions.txt rather than being silently tolerated:
wingsail-controller 6.16.1 CubeMX cannot downgrade a project, so getting
back to 6.15.0 needs a deliberate .ioc revert
and a re-verify against the flashed board
FDCAN_Serial 6.12.1 upgrade also moves FW_U5 V1.6.0 -> V1.8.0
Communication Module 6.10.0 two firmware packs behind, and carries the
I2C3/I2C4 drift that must be fixed in the same
regeneration
One source of truth for the toolchain. nix/stm32cubemx.nix is the nixpkgs derivation pinned back to 6.15.0, the version this repo's .ioc files target; nixpkgs itself ships 6.17.0. ST still serves the 6.15.0 archive, so the pin is a version and hash change, nothing exotic. Pinning matters because CubeMX raises a modal migrate/continue/cancel dialog whenever a project's MxCube.Version differs from the running CubeMX, and it does so even in -q script mode, which hangs a headless run. Everyone being on the same CubeMX is what stops that happening. Two devshells: default CubeMX, arm-none-eabi, openocd, stlink, host test tooling ci gcc, make, python3 only CI uses .#ci rather than .#default on purpose. Neither the host tests nor the .ioc check need CubeMX or the cross toolchain, and CubeMX alone is a ~1GB unfree download that would dominate every run. Verified locally through the flake: both CI jobs pass, all six test suites green.
Placeholder hash replaced with the value nix reported. Verified: the package builds, and loading a 6.15.0 project returns OK with no migrate dialog.
Atlas sensor board firmware. Merges clean against the other three module branches, no conflicts. sense-integrated rather than sense-working-branch: the two are siblings forked from the same commit on main, not ancestor and descendant. sense-working-branch is Michael Greenough's five-day prototype from October 2025 and has been dead since; sense-integrated is the line that continued (Alisha Siddiqui, then Aayush Kolharkar) through to the new SENSE board, and is what the hardware evidence points at. Note the flashed sense module still does not match this branch. Its firmware contains a "Heartbeat!!" literal that exists nowhere in sense-integrated at any commit, so the board is running an unpushed local build. Reflashing from this branch would settle it.
The host-tests job failed on the runner while passing locally: features.h:435:4: error: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Werror=cpp] firmware/tests builds at -O0 with -Werror, and nixpkgs' cc-wrapper adds -D_FORTIFY_SOURCE by default. glibc then warns that fortify needs optimisation, and -Werror promotes that to an error. It did not reproduce on the NixOS host even with --ignore-environment, because the ambient hardening defaults differ from a plain Ubuntu runner. Setting hardeningDisable explicitly makes both behave the same rather than depending on where the shell happens to be entered. Verified: NIX_HARDENING_ENABLE no longer lists fortify, and all six suites pass in a clean shell.
sailbot-eleclead
previously approved these changes
Aug 16, 2026
CubeMX hardcodes $HOME/.stm32cubemx (device database, ~1.2GB) and $HOME/STM32Cube (firmware packs). Redirecting HOME does not move them: the JDK resolves user.home from the password database, not the environment. Bind-mounting inside the bubblewrap sandbox the package already uses does work. State now lives under $XDG_DATA_HOME/stm32cubemx. All that remains in the home directory is two empty mount points, which bwrap has to create inside the bound /home and cannot be avoided while CubeMX insists on those paths. The wrapper that creates the source directories is single-quoted so $HOME expands when it runs rather than during the build, where HOME is /homeless-shelter. Verified: config load returns OK, writes land in XDG, and the home directory gains only two 0-byte directories.
Firmware flashed for an on-water test must come from a tagged commit on main, not a working branch or a local build. A tag is the only reliable answer to "what was running?" after the fact. This session found the concrete case: the sense board runs code containing a string literal that exists on no branch, so it cannot be reconstructed.
georgesleen
force-pushed
the
integration/modules-to-main
branch
from
August 16, 2026 06:35
7f2c783 to
1eb479e
Compare
sailbot-eleclead
approved these changes
Aug 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Single integration branch bringing all four module branches into
maintogether, so the conflicts between them are resolved once, deliberately,
rather than four times by whoever merges last.
Supersedes #59 (wingsail), #60 (rudder) and #61 (pdb). All four tips are
contained here:
rudder-working-branchf062937pdb-working-branche31d2c2sense-integratede70c420wingsail-working-branch334ee7fsense-integratedis used rather thansense-working-branch. The two aresiblings forked from the same commit on
main, not ancestor and descendant.sense-working-branchis a five-day prototype from October 2025, dead since;sense-integratedis the line that continued through to the new SENSE board.It also adds CI and a flake, described at the end.
Merged in the order rudder -> pdb -> wingsail -> sense. Rudder, pdb and sense do not conflict
with each other or with the result at all; every conflict is wingsail against the others.
How conflicts were resolved
By ownership: each controller project goes to the branch that develops it, and
shared modules go to the version that is actually safe to share.
firmware/com-modules/CANFD/can.c-> rudder. This file does not exist onmainand was added independently on the branches, so it was an add/addconflict. Rudder's copy wins for two concrete reasons:
__weakonHAL_FDCAN_RxFifo0CallbackandHAL_TIM_PeriodElapsedCallback(rudder 2, wingsail 0, pdb 0). Without__weak, any controller project defining its own callback gets a duplicatesymbol at link time, which defeats the purpose of a shared module.
(
can_heartbeat_tx_failures++) rather than callingError_Handler(). On thebench with no CAN ACK, the other two fault the whole board every 10 seconds.
library-test-projectcan.h/can.c-> wingsail. Note for reviewers:rudder's committed copies of these two files contain unresolved conflict
markers (2 in
can.h, 12 incan.c). Wingsail's are clean, so ownership wasoverridden here. Worth fixing on
rudder-working-branchindependently of thisPR.
firmware/PLRS-IMU-> rudder (e01ef3b). Wingsail carried a160000gitlink with no
.gitmodulesfile at all, so the submodule was unusablefrom a fresh clone and git reported "no merge base". Rudder ships a valid
.gitmodulesand a newer commit, and wingsail does not reference PLRS-IMU.Rest:
wingsail-controller/*anddrv-modules/nmea0183/*to wingsail;rudder-controller/.cproject,BNO055-imu,motor-base-PIDto rudder;.gitignoreis the union of both sides; the twostm32u5xx_hal_tim*.crenamecollisions were restored from clean vendored copies.
Verified afterwards: zero conflict markers anywhere in the tree,
can.chasrudder's 2
__weakmarkers and the non-fatal heartbeat, wingsail'smain.cretains its BRITER integration, and
.gitmodulesis present.Known issues carried in, not introduced here
can.cis duplicated: 3 copies on rudder and wingsail, 4 on pdb. pdb'scommit
e31d2c2"Remove hard fault on heart beat CAN error" fixed aproject-local copy, while its shared copy still calls
Error_Handler().Consolidating these should be follow-up work.
can.c. Worth porting back on top, it is genuinely useful..exebinaries (~346 KB each) are tracked underrudder-control-model/, andnmea-sample.txtis 85,193 lines.Per the README this needs two sign-offs, one from an ELEC lead.
CI and toolchain (added on this branch)
There was no CI in this repo before. Two jobs now run on every PR, both from
the flake so local and CI use the same environment:
.ioc's declared peripherals against theMX_<PERIPH>_Initfunctions in its generatedmain.c, and pins the CubeMXversion. Running CubeMX itself in CI is not viable: it raises a modal
migrate/continue/cancel dialog on any version mismatch, even in
-qscriptmode, so a headless run just blocks.
and runs all six suites.
canfd_testpreviously did not compile, so the CANFD module, the one piece ofcode shared by every controller, had no coverage. The stub HAL now provides
__weak, the TIM types and the FDCAN bus-error notification bits, and all sixsuites pass under
-Werror.flake.nixpins STM32CubeMX to 6.15.0 (nixpkgs ships 6.17.0) vianix/stm32cubemx.nix. Four of seven projects are already on 6.15.0. The threethat are not are recorded in
tools/ioc-version-exceptions.txtwith reasons;that file is scaffolding and should be deleted once every project is
regenerated on the pinned version.
Firmware verification status
Heartbeat!!literal that exists nowhere insense-integratedat any commit, so it is running an unpushed local build