Sync inav to Gitea
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
# Parameter Groups System
|
||||
|
||||
## Overview
|
||||
|
||||
Parameter Groups (PG) is INAV's system for managing persistent configuration settings. Each configuration struct is registered with a unique ID and version number, stored in EEPROM/flash, and automatically validated on boot.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**When modifying a parameter group struct:**
|
||||
- ✅ **Increment version** - Safest option, always works
|
||||
- ⚠️ **Don't increment** - Only safe for comments or non-structural changes
|
||||
|
||||
**Key files:**
|
||||
- `src/main/config/parameter_group.h` - Macros and registry structure
|
||||
- `src/main/config/parameter_group.c` - Runtime load/store functions
|
||||
- `src/main/config/parameter_group_ids.h` - PGN definitions
|
||||
- `src/main/fc/settings.yaml` - Maps CLI settings to PG fields
|
||||
|
||||
## How It Works
|
||||
|
||||
### Registration
|
||||
|
||||
Parameter groups use linker sections to build a compile-time registry:
|
||||
|
||||
```c
|
||||
// In yourfeature.h
|
||||
typedef struct yourFeatureConfig_s {
|
||||
uint8_t enabled;
|
||||
uint16_t rate;
|
||||
} yourFeatureConfig_t;
|
||||
|
||||
PG_DECLARE(yourFeatureConfig_t, yourFeatureConfig);
|
||||
|
||||
// In yourfeature.c
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(
|
||||
yourFeatureConfig_t,
|
||||
yourFeatureConfig,
|
||||
PG_YOUR_FEATURE_CONFIG, // Unique ID from parameter_group_ids.h
|
||||
0 // Version number
|
||||
);
|
||||
|
||||
PG_RESET_TEMPLATE(yourFeatureConfig_t, yourFeatureConfig,
|
||||
.enabled = 1,
|
||||
.rate = 100
|
||||
);
|
||||
```
|
||||
|
||||
### Version Checking
|
||||
|
||||
On boot, `pgLoad()` validates versions before loading settings:
|
||||
|
||||
```c
|
||||
void pgLoad(const pgRegistry_t* reg, int profileIndex,
|
||||
const void *from, int size, int version)
|
||||
{
|
||||
pgReset(reg, profileIndex); // Always reset to defaults first
|
||||
|
||||
if (version == pgVersion(reg)) {
|
||||
// Only copy if versions match
|
||||
const int take = MIN(size, pgSize(reg));
|
||||
memcpy(pgOffset(reg, profileIndex), from, take);
|
||||
}
|
||||
// If version mismatch: defaults remain, no corruption
|
||||
}
|
||||
```
|
||||
|
||||
**Key behavior:** Version mismatch causes settings to remain at defaults. This prevents corruption when struct layout changes.
|
||||
|
||||
## Version Management
|
||||
|
||||
### When to Increment Version
|
||||
|
||||
Version numbers are stored in the top 4 bits of the PGN field (valid range: 0-15).
|
||||
|
||||
**The safe rule:** When modifying a parameter group struct, increment the version.
|
||||
|
||||
**Changes requiring version increment:**
|
||||
- Removing a field
|
||||
- Changing field type or size
|
||||
- Reordering fields
|
||||
- Adding packing attributes
|
||||
|
||||
**Example - Removing a field:**
|
||||
|
||||
```c
|
||||
// Before: version 4
|
||||
typedef struct blackboxConfig_s {
|
||||
uint16_t rate_num;
|
||||
uint16_t rate_denom;
|
||||
uint8_t device;
|
||||
uint8_t invertedCardDetection; // Removing this
|
||||
uint32_t includeFlags;
|
||||
int8_t arm_control;
|
||||
} blackboxConfig_t;
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 4);
|
||||
|
||||
// After: version 5 (MUST increment!)
|
||||
typedef struct blackboxConfig_s {
|
||||
uint16_t rate_num;
|
||||
uint16_t rate_denom;
|
||||
uint8_t device;
|
||||
// invertedCardDetection removed - field offsets changed!
|
||||
uint32_t includeFlags; // Now at different offset
|
||||
int8_t arm_control; // Now at different offset
|
||||
} blackboxConfig_t;
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 5);
|
||||
```
|
||||
|
||||
**Why:** Without version increment, `pgLoad()` sees matching versions (4==4) and copies old data, but field offsets have changed. Result: `includeFlags` reads wrong bytes from EEPROM, causing corruption.
|
||||
|
||||
With version increment (4→5), `pgLoad()` detects mismatch and keeps defaults instead.
|
||||
|
||||
### Changes NOT Requiring Version Increment
|
||||
|
||||
- Comments only
|
||||
- Default values in `PG_RESET_TEMPLATE` (doesn't affect EEPROM layout)
|
||||
- settings.yaml entries (CLI mapping, not struct layout)
|
||||
|
||||
### Technical Note on Appending
|
||||
|
||||
The `pgLoad()` function uses `MIN(size, pgSize(reg))` when copying data. This means:
|
||||
- If new firmware has larger struct, it copies available bytes and keeps defaults for new fields
|
||||
- If new firmware has smaller struct, it copies only what fits
|
||||
|
||||
This behavior theoretically allows appending fields at the end without version increment. However, **the recommended practice is to always increment** unless you have specific reason not to and understand the implications.
|
||||
|
||||
## Complete Example
|
||||
|
||||
### yourfeature.h
|
||||
```c
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "config/parameter_group.h"
|
||||
|
||||
typedef struct yourFeatureConfig_s {
|
||||
uint8_t enabled;
|
||||
uint16_t updateRate;
|
||||
uint32_t flags;
|
||||
} yourFeatureConfig_t;
|
||||
|
||||
PG_DECLARE(yourFeatureConfig_t, yourFeatureConfig);
|
||||
```
|
||||
|
||||
### yourfeature.c
|
||||
```c
|
||||
#include "yourfeature.h"
|
||||
#include "config/parameter_group_ids.h"
|
||||
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(
|
||||
yourFeatureConfig_t,
|
||||
yourFeatureConfig,
|
||||
PG_YOUR_FEATURE_CONFIG,
|
||||
0
|
||||
);
|
||||
|
||||
PG_RESET_TEMPLATE(yourFeatureConfig_t, yourFeatureConfig,
|
||||
.enabled = 1,
|
||||
.updateRate = 100,
|
||||
.flags = 0
|
||||
);
|
||||
|
||||
void yourFeatureInit(void)
|
||||
{
|
||||
if (!yourFeatureConfig()->enabled) {
|
||||
return;
|
||||
}
|
||||
// Use configuration...
|
||||
}
|
||||
```
|
||||
|
||||
### parameter_group_ids.h
|
||||
```c
|
||||
typedef enum {
|
||||
// ... existing entries ...
|
||||
PG_YOUR_FEATURE_CONFIG = 150, // Choose unused ID
|
||||
// ...
|
||||
} pgn_e;
|
||||
```
|
||||
|
||||
### settings.yaml
|
||||
```yaml
|
||||
- name: your_feature_enable
|
||||
description: "Enable yourFeature"
|
||||
field: yourFeatureConfig.enabled
|
||||
type: uint8_t
|
||||
min: 0
|
||||
max: 1
|
||||
default_value: 1
|
||||
|
||||
- name: your_feature_rate
|
||||
description: "Update rate in Hz"
|
||||
field: yourFeatureConfig.updateRate
|
||||
type: uint16_t
|
||||
min: 1
|
||||
max: 1000
|
||||
default_value: 100
|
||||
```
|
||||
|
||||
## Accessing Configuration
|
||||
|
||||
### Read-only (preferred)
|
||||
```c
|
||||
if (yourFeatureConfig()->enabled) {
|
||||
processAtRate(yourFeatureConfig()->updateRate);
|
||||
}
|
||||
```
|
||||
|
||||
### Mutable (use sparingly)
|
||||
```c
|
||||
yourFeatureConfigMutable()->updateRate = newRate;
|
||||
```
|
||||
|
||||
## Registration Macros
|
||||
|
||||
| Macro | Use |
|
||||
|-------|-----|
|
||||
| `PG_DECLARE(type, name)` | Declare system PG in header |
|
||||
| `PG_DECLARE_PROFILE(type, name)` | Declare profile PG in header |
|
||||
| `PG_REGISTER_WITH_RESET_TEMPLATE(...)` | Register with template defaults |
|
||||
| `PG_REGISTER_WITH_RESET_FN(...)` | Register with custom reset function |
|
||||
| `PG_RESET_TEMPLATE(type, name, ...)` | Define default values |
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Boolean Fields
|
||||
```c
|
||||
uint8_t enabled; // Use uint8_t, not bool (EEPROM needs fixed sizes)
|
||||
```
|
||||
|
||||
### Enums
|
||||
```c
|
||||
typedef enum { MODE_A = 0, MODE_B = 1 } mode_e;
|
||||
uint8_t mode; // Store enum as uint8_t
|
||||
```
|
||||
|
||||
### Bitfields
|
||||
```c
|
||||
#define FLAG_A (1 << 0)
|
||||
#define FLAG_B (1 << 1)
|
||||
uint32_t flags;
|
||||
```
|
||||
|
||||
## Testing Version Changes
|
||||
|
||||
When incrementing a version:
|
||||
|
||||
1. Flash old firmware, configure non-default settings, save
|
||||
2. Flash new firmware with incremented version
|
||||
3. Verify settings reset to defaults (not corrupted)
|
||||
4. Check for errors in CLI
|
||||
|
||||
## See Also
|
||||
|
||||
- `src/main/config/parameter_group.h` - Full macro definitions
|
||||
- `src/main/config/parameter_group.c` - Implementation
|
||||
- Betaflight PG documentation: https://betaflight.com/docs/development/ParameterGroups
|
||||
Reference in New Issue
Block a user