Skip to content

Commit 52f3e94

Browse files
authored
Merge branch 'development' into feat/newInputCapture
2 parents 03e49c8 + 3c62efa commit 52f3e94

10 files changed

Lines changed: 764 additions & 169 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
release: patch
2+
summary: Fix incorrect GPIO alternate-function availability bitmaps
3+
4+
Correct the STM32H723 pin alternate-function masks in `Pin.hpp` so GPIO
5+
configuration reflects the actual AF support per pin.

.claude/commands/new-driver.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
Create a new ST-LIB hardware driver for: $ARGUMENTS
2+
3+
Use ADC as the reference implementation:
4+
- `Inc/HALAL/Services/ADC/ADC.hpp` — service header pattern
5+
- `Tests/adc_test.cpp` — test pattern with mocked drivers
6+
7+
### Step 1 — Service header `Inc/HALAL/Services/[Module]/[Module].hpp`
8+
9+
- Define `[Module]Domain` struct (wraps everything)
10+
- Define `Entry` struct: compile-time config per peripheral instance (pin, mode, output pointer, etc.)
11+
- Define `Config` struct: fully resolved config after `build()` (all AUTO fields resolved)
12+
- Define enums for peripheral IDs, operating modes, resolutions, etc.
13+
- Implement `consteval build<N>(std::span<const Entry, N>) -> std::array<Config, N>`
14+
- Resolve AUTO fields (pin → peripheral/channel lookup tables)
15+
- Validate constraints at compile time — use `compile_error()` for violations
16+
- Guard hardware-specific declarations with `#ifdef HAL_[MODULE]_MODULE_ENABLED`
17+
- Include `hal_wrapper.h` at the top
18+
19+
### Step 2 — Service implementation `Src/HALAL/Services/[Module]/[Module].cpp`
20+
21+
- HAL handle declarations (`extern [MODULE]_HandleTypeDef h[module]N`)
22+
- `start(const Config& cfg)` function: initialize HAL, configure DMA if needed
23+
- Runtime operations: `read()`, `write()`, `get_value()`, etc.
24+
- Use `#ifdef SIM_ON` to call mocked functions instead of real HAL
25+
26+
### Step 3 — MockedDriver `Inc/MockedDrivers/mocked_hal_[module].hpp`
27+
28+
- In-memory state arrays replacing HAL registers
29+
- Init function called instead of HAL init in `SIM_ON` mode
30+
- Control functions for tests: `[module]_set_*(idx, value)`, `[module]_get_*(idx)`
31+
- Time simulation if the peripheral has timing behavior: `[module]_advance_time_ns(ns)`
32+
- Callback/interrupt simulation if needed
33+
34+
### Step 4 — Tests `Tests/[module]_test.cpp`
35+
36+
```cpp
37+
#include <gtest/gtest.h>
38+
#include "HALAL/Services/[Module]/[Module].hpp"
39+
#include "MockedDrivers/mocked_hal_[module].hpp"
40+
41+
namespace ST_LIB::TestErrorHandler { void reset(); void set_fail_on_error(bool); }
42+
43+
namespace {
44+
// Declare test configs at namespace scope (constexpr can't be local)
45+
inline float test_output = 0.0f;
46+
constexpr std::array<[Module]Domain::Entry, 1> test_entry{{ ... }};
47+
constexpr auto test_cfg = [Module]Domain::build<1>(std::span{test_entry});
48+
static_assert(test_cfg[0].peripheral == ...); // verify compile-time resolution
49+
}
50+
51+
TEST(ModuleTest, CompileTimeConfig) { ... }
52+
TEST(ModuleTest, BasicReadWrite) { ... }
53+
TEST(ModuleTest, ErrorOnInvalidConfig) {
54+
ST_LIB::TestErrorHandler::set_fail_on_error(true);
55+
// trigger invalid config...
56+
ST_LIB::TestErrorHandler::reset();
57+
}
58+
```
59+
60+
Add to `Tests/CMakeLists.txt`:
61+
```cmake
62+
add_executable([module]_test [module]_test.cpp)
63+
target_link_libraries([module]_test PRIVATE stlib GTest::gtest_main)
64+
add_test(NAME [Module]Test COMMAND [module]_test)
65+
```
66+
67+
### Step 5 — Register in HALAL
68+
69+
- Add `#include "HALAL/Services/[Module]/[Module].hpp"` to `Inc/HALAL/HALAL.hpp`
70+
- Add `[Module]Domain::start()` call in `Src/HALAL/HALAL.cpp` inside `common_start()`
71+
- Check initialization order: DMA must be started before services that use it
72+
73+
### Verification
74+
75+
```bash
76+
cmake --preset simulator
77+
cmake --build --preset simulator
78+
ctest --preset simulator-all
79+
```

.claude/commands/new-test.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Write a new GTest test for ST-LIB module: $ARGUMENTS
2+
3+
1. Read the most relevant existing test first to understand the exact patterns:
4+
- `Tests/adc_test.cpp` — for ADC-like services (compile-time config + DMA)
5+
- `Tests/dma2_test.cpp` — for DMA-focused tests
6+
- `Tests/spi2_test.cpp` — for SPI/communication tests
7+
- `Tests/adc_sensor_test.cpp` — for higher-level sensor abstractions
8+
9+
2. Read the service header (`Inc/HALAL/Services/[Module]/[Module].hpp`) to understand the API
10+
11+
3. Read the MockedDriver header (`Inc/MockedDrivers/mocked_hal_[module].hpp`) to understand what control/injection functions are available
12+
13+
4. Write the test file `Tests/[module]_test.cpp`:
14+
15+
**Required structure:**
16+
- All `constexpr` test configs at **namespace scope**, not inside TEST bodies (constexpr variables cannot be local)
17+
- `inline float` output variables at namespace scope
18+
- For DMA-based services: use `merge_dma_entries<TotalN>(base_span, extra_array...)` pattern from `adc_test.cpp` when combining multiple peripheral DMA configs
19+
20+
**Recommended test cases:**
21+
- `CompileTimeConfig`: verify `build()` resolves AUTO fields correctly via `static_assert` + `EXPECT_EQ`
22+
- `BasicOperation`: inject a value via mocked driver, call the service, verify output
23+
- `MultiInstance`: test two simultaneous instances don't interfere
24+
- `ErrorOnInvalidConfig`: set `TestErrorHandler::set_fail_on_error(true)`, trigger invalid config, verify error was called
25+
26+
**Error handler pattern:**
27+
```cpp
28+
namespace ST_LIB::TestErrorHandler {
29+
void reset();
30+
void set_fail_on_error(bool enabled);
31+
extern int call_count;
32+
}
33+
// In test:
34+
ST_LIB::TestErrorHandler::set_fail_on_error(true);
35+
// ... code that should trigger error ...
36+
EXPECT_GT(ST_LIB::TestErrorHandler::call_count, 0);
37+
ST_LIB::TestErrorHandler::reset();
38+
```
39+
40+
5. Register in `Tests/CMakeLists.txt`:
41+
```cmake
42+
add_executable([module]_test [module]_test.cpp)
43+
target_link_libraries([module]_test PRIVATE stlib GTest::gtest_main)
44+
add_test(NAME [Module]Test COMMAND [module]_test)
45+
```
46+
47+
6. Run and verify:
48+
```bash
49+
cmake --build --preset simulator
50+
ctest --preset simulator-all --output-on-failure
51+
```

.claude/commands/pin-mapping.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Show the ADC peripheral and channel mapping for GPIO pin: $ARGUMENTS
2+
3+
1. Read `Inc/HALAL/Services/ADC/ADC.hpp` and find the `pin_map` constexpr lookup table
4+
5+
2. Look up the requested pin and report:
6+
- Which ADC peripheral it maps to: `ADC_1`, `ADC_2`, or `ADC_3`
7+
- Which channel number (e.g. `CH16`)
8+
- Whether this pin is shared with another function (PWM, SPI, etc.) that could conflict
9+
10+
3. Check `Tests/adc_test.cpp` for any existing `static_assert` that already validates this mapping
11+
12+
4. Explain the implications for multi-channel use:
13+
- Pins on the **same ADC peripheral** → share one DMA stream, conversion is sequential (scan mode)
14+
- Pins on **different ADC peripherals** → separate DMA streams, conversions run in parallel
15+
- Maximum 16 channels per peripheral on STM32H723
16+
17+
5. Show the exact `ADCDomain::Entry` snippet to use this pin correctly:
18+
```cpp
19+
inline float my_output = 0.0f;
20+
21+
constexpr std::array<ADCDomain::Entry, 1> entry{{
22+
{.gpio_idx = 0,
23+
.pin = ST_LIB::[PIN],
24+
.peripheral = ADCDomain::Peripheral::AUTO,
25+
.channel = ADCDomain::Channel::AUTO,
26+
.resolution = ADCDomain::Resolution::BITS_12,
27+
.sample_time = ADCDomain::SampleTime::CYCLES_8_5,
28+
.prescaler = ADCDomain::ClockPrescaler::DIV1,
29+
.sample_rate_hz = 0,
30+
.output = &my_output}
31+
}};
32+
constexpr auto cfg = ADCDomain::build<1>(std::span{entry});
33+
// Confirm the resolved mapping:
34+
static_assert(cfg[0].peripheral == ADCDomain::Peripheral::[RESOLVED]);
35+
static_assert(cfg[0].channel == ADCDomain::Channel::[RESOLVED]);
36+
```
37+
38+
6. If the pin is **not in the pin_map** (not ADC-capable on STM32H723), say so clearly and suggest the nearest ADC-capable pins.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Claude Code Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, ready_for_review, reopened]
6+
7+
jobs:
8+
claude-review:
9+
if: github.event.pull_request.user.login == 'jsaegar'
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: read
13+
pull-requests: read
14+
issues: read
15+
id-token: write
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 1
22+
23+
- name: Run Claude Code Review
24+
id: claude-review
25+
uses: anthropics/claude-code-action@v1
26+
with:
27+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
28+
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
29+
plugins: 'code-review@claude-code-plugins'
30+
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'

.github/workflows/claude.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Claude Code
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
issues:
9+
types: [opened, assigned]
10+
pull_request_review:
11+
types: [submitted]
12+
13+
jobs:
14+
claude:
15+
if: |
16+
github.actor == 'jsaegar' && (
17+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
18+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
19+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
20+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
21+
)
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
pull-requests: read
26+
issues: read
27+
id-token: write
28+
actions: read # Required for Claude to read CI results on PRs
29+
steps:
30+
- name: Checkout repository
31+
uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 1
34+
35+
- name: Run Claude Code
36+
id: claude
37+
uses: anthropics/claude-code-action@v1
38+
with:
39+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
40+
41+
# This is an optional setting that allows Claude to read CI results on PRs
42+
additional_permissions: |
43+
actions: read

0 commit comments

Comments
 (0)