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,409 @@
|
||||
# API Definition Maintenance Guide
|
||||
|
||||
## Single Source of Truth
|
||||
|
||||
All INAV JavaScript API definitions are centralized in:
|
||||
```
|
||||
js/transpiler/api/definitions/
|
||||
```
|
||||
|
||||
**When adding new INAV features, you only need to edit files in this directory.**
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
js/transpiler/api/definitions/
|
||||
├── index.js # Exports all definitions
|
||||
├── events.js # Event handlers (timer, whenChanged, etc.)
|
||||
├── flight.js # Flight parameters (read-only)
|
||||
├── gvar.js # Global variables (read/write)
|
||||
├── helpers.js # Math & utility functions
|
||||
├── override.js # Override settings (writable)
|
||||
├── pid.js # Programming PID controllers
|
||||
├── rc.js # RC channels (read/write)
|
||||
└── waypoint.js # Waypoint navigation
|
||||
```
|
||||
|
||||
## Definition Format
|
||||
|
||||
Each definition file exports objects following this structure:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
propertyName: {
|
||||
type: 'number' | 'boolean' | 'string' | 'object' | 'function',
|
||||
desc: 'Human-readable description',
|
||||
unit: 'Unit of measurement (optional)',
|
||||
readonly: true | false,
|
||||
range: [min, max], // Optional: valid value range
|
||||
inavOperand: {
|
||||
type: 2, // OPERAND_TYPE constant
|
||||
value: 1 // Operand value for INAV
|
||||
},
|
||||
inavOperation: 27, // Optional: OPERATION constant
|
||||
},
|
||||
|
||||
// Nested objects
|
||||
nestedObject: {
|
||||
type: 'object',
|
||||
desc: 'Description',
|
||||
properties: {
|
||||
subProperty: {
|
||||
type: 'number',
|
||||
desc: 'Sub-property description',
|
||||
// ... same structure as above
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## What Uses These Definitions
|
||||
|
||||
### 1. **Semantic Analyzer** (`analyzer.js`)
|
||||
- Validates property access
|
||||
- Checks writable properties
|
||||
- Validates value ranges
|
||||
- **Auto-updates when definitions change**
|
||||
|
||||
### 2. **Type Definitions** (`types.js`)
|
||||
- Generates TypeScript definitions for Monaco Editor
|
||||
- Provides IntelliSense autocomplete
|
||||
- **Auto-generates from definitions**
|
||||
|
||||
### 3. **Code Generator** (`codegen.js`)
|
||||
- Maps JavaScript to INAV operands
|
||||
- Uses `inavOperand` and `inavOperation` fields
|
||||
- **Requires manual update for new operations**
|
||||
|
||||
### 4. **Decompiler** (`decompiler.js`)
|
||||
- Reverse maps INAV to JavaScript
|
||||
- Uses operand mappings from API definitions
|
||||
- **Auto-updates when definitions change**
|
||||
|
||||
## Adding a New Property
|
||||
|
||||
### Example: Adding `flight.compassHeading`
|
||||
|
||||
**1. Edit `js/transpiler/api/definitions/flight.js`:**
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
// ... existing properties ...
|
||||
|
||||
compassHeading: {
|
||||
type: 'number',
|
||||
unit: '°',
|
||||
desc: 'Compass heading in degrees (0-359)',
|
||||
readonly: true,
|
||||
range: [0, 359],
|
||||
inavOperand: {
|
||||
type: 2, // OPERAND_TYPE.FLIGHT
|
||||
value: 40 // FLIGHT_PARAM.COMPASS_HEADING
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**2. Update `inav_constants.js` (if needed):**
|
||||
|
||||
Only if adding a completely new INAV firmware feature:
|
||||
|
||||
```javascript
|
||||
const FLIGHT_PARAM = {
|
||||
// ... existing params ...
|
||||
COMPASS_HEADING: 40
|
||||
};
|
||||
|
||||
const FLIGHT_PARAM_NAMES = {
|
||||
// ... existing names ...
|
||||
[FLIGHT_PARAM.COMPASS_HEADING]: 'compassHeading'
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**3. That's it!**
|
||||
|
||||
The following automatically update:
|
||||
- ✅ Semantic analyzer validates `flight.compassHeading`
|
||||
- ✅ TypeScript definitions show in autocomplete
|
||||
- ✅ Range checking works automatically
|
||||
- ✅ Decompiler recognizes the property
|
||||
|
||||
## Adding a New Writable Property
|
||||
|
||||
### Example: Adding `override.vtx.frequency`
|
||||
|
||||
**1. Edit `js/transpiler/api/definitions/override.js`:**
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
// ... existing properties ...
|
||||
|
||||
vtx: {
|
||||
type: 'object',
|
||||
desc: 'VTX control',
|
||||
properties: {
|
||||
power: { /* ... */ },
|
||||
band: { /* ... */ },
|
||||
channel: { /* ... */ },
|
||||
|
||||
// NEW PROPERTY
|
||||
frequency: {
|
||||
type: 'number',
|
||||
unit: 'MHz',
|
||||
desc: 'VTX frequency in MHz',
|
||||
readonly: false, // Writable!
|
||||
range: [5000, 6000],
|
||||
inavOperation: 50 // New operation code
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**2. Update `inav_constants.js`:**
|
||||
|
||||
```javascript
|
||||
const OPERATION = {
|
||||
// ... existing operations ...
|
||||
OVERRIDE_VTX_FREQUENCY: 50
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**3. Update `codegen.js` (manual):**
|
||||
|
||||
Add code generation logic:
|
||||
|
||||
```javascript
|
||||
// In generateAction() method
|
||||
if (stmt.target === 'inav.override.vtx.frequency') {
|
||||
return this.pushLogicCommand(
|
||||
OPERATION.OVERRIDE_VTX_FREQUENCY,
|
||||
{ type: OPERAND_TYPE.VALUE, value: 0 },
|
||||
this.valueOperand(stmt.value),
|
||||
activatorId
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Adding a New Top-Level API Object
|
||||
|
||||
### Example: Adding `inav.sensors`
|
||||
|
||||
**1. Create `js/transpiler/api/definitions/sensors.js`:**
|
||||
|
||||
```javascript
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
acc: {
|
||||
type: 'boolean',
|
||||
desc: 'Accelerometer sensor detected',
|
||||
readonly: true,
|
||||
inavOperand: {
|
||||
type: 2, // FLIGHT
|
||||
value: 50 // New param ID
|
||||
}
|
||||
},
|
||||
|
||||
mag: {
|
||||
type: 'boolean',
|
||||
desc: 'Magnetometer sensor detected',
|
||||
readonly: true,
|
||||
inavOperand: {
|
||||
type: 2,
|
||||
value: 51
|
||||
}
|
||||
}
|
||||
|
||||
// ... more sensors
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**2. Update `js/transpiler/api/definitions/index.js`:**
|
||||
|
||||
```javascript
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
flight: require('./inav.flight.js'),
|
||||
override: require('./inav.override.js'),
|
||||
rc: require('./rc.js'),
|
||||
gvar: require('./gvar.js'),
|
||||
waypoint: require('./inav.waypoint.js'),
|
||||
pid: require('./pid.js'),
|
||||
helpers: require('./helpers.js'),
|
||||
events: require('./events.js'),
|
||||
sensors: require('./sensors.js') // ADD THIS
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
**3. Update TypeScript types in `types.js` generation:**
|
||||
|
||||
The type generator should automatically pick it up, but verify:
|
||||
|
||||
```javascript
|
||||
// In generateTypeDefinitions()
|
||||
dts += generateInterfaceFromDefinition('sensors', apiDefinitions.sensors);
|
||||
|
||||
```
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
When adding/modifying API definitions:
|
||||
|
||||
- [ ] Property has correct `type`
|
||||
- [ ] Has descriptive `desc`
|
||||
- [ ] Has `unit` if applicable
|
||||
- [ ] `readonly` flag is correct
|
||||
- [ ] `range` is specified for numeric values
|
||||
- [ ] `inavOperand` maps to correct INAV constant
|
||||
- [ ] `inavOperation` specified for writable properties
|
||||
- [ ] Updated `index.js` if new file
|
||||
- [ ] Updated `inav_constants.js` if new INAV feature
|
||||
- [ ] Updated `codegen.js` for new writable properties
|
||||
- [ ] Tested with sample code
|
||||
- [ ] TypeScript definitions generate correctly
|
||||
|
||||
## Testing Changes
|
||||
|
||||
After modifying definitions:
|
||||
|
||||
```javascript
|
||||
// 1. Test semantic analysis
|
||||
const code = `
|
||||
if (sensors.acc) {
|
||||
// ...
|
||||
}
|
||||
`;
|
||||
|
||||
const transpiler = new Transpiler();
|
||||
const result = transpiler.transpile(code);
|
||||
// Should not have errors
|
||||
|
||||
// 2. Test type generation
|
||||
const { generateTypeDefinitions } = require('./api/types.js');
|
||||
const dts = generateTypeDefinitions(apiDefinitions);
|
||||
// Should include new properties
|
||||
|
||||
// 3. Test in Monaco Editor
|
||||
// Open configurator, verify autocomplete shows new properties
|
||||
|
||||
```
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### ❌ Wrong: Editing analyzer.js directly
|
||||
```javascript
|
||||
// DON'T DO THIS in analyzer.js:
|
||||
this.inavAPI = {
|
||||
'flight': {
|
||||
properties: ['homeDistance', 'newProperty'] // Hard-coded!
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### ✅ Right: Edit definition file
|
||||
```javascript
|
||||
// DO THIS in inav.flight.js:
|
||||
module.exports = {
|
||||
newProperty: {
|
||||
type: 'number',
|
||||
desc: 'New property',
|
||||
// ...
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### ❌ Wrong: Duplicating definitions
|
||||
```javascript
|
||||
// DON'T duplicate in multiple files
|
||||
// decompiler.js - NO!
|
||||
const FLIGHT_PARAMS = {
|
||||
1: 'homeDistance'
|
||||
};
|
||||
|
||||
// analyzer.js - NO!
|
||||
properties: ['homeDistance']
|
||||
|
||||
```
|
||||
|
||||
### ✅ Right: Use centralized definitions
|
||||
```javascript
|
||||
// DO THIS - import from definitions
|
||||
const apiDefinitions = require('./../api/definitions/index.js');
|
||||
const flightDef = apiDefinitions.flight;
|
||||
|
||||
```
|
||||
|
||||
## File Dependencies
|
||||
|
||||
```
|
||||
js/transpiler/api/definitions/
|
||||
├── index.js
|
||||
├── events.js
|
||||
├── flight.js
|
||||
├── gvar.js
|
||||
├── helpers.js
|
||||
├── override.js
|
||||
├── pid.js
|
||||
├── rc.js
|
||||
└── waypoint.js
|
||||
↓
|
||||
Used by:
|
||||
├── analyzer.js (validation)
|
||||
├── types.js (TypeScript generation)
|
||||
├── codegen.js (code generation)
|
||||
└── decompiler.js (via inav_constants.js)
|
||||
```
|
||||
|
||||
## Migration from Hardcoded Values
|
||||
|
||||
If you find hardcoded API definitions elsewhere in the code:
|
||||
|
||||
1. **Identify the hardcoded values**
|
||||
2. **Check if they exist in `api/definitions/`**
|
||||
3. **If not, add them to appropriate definition file**
|
||||
4. **Replace hardcoded values with imports**
|
||||
5. **Test thoroughly**
|
||||
6. **Remove old hardcoded definitions**
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
// Before (hardcoded in analyzer.js)
|
||||
this.inavAPI = {
|
||||
'flight': {
|
||||
properties: ['homeDistance', 'altitude']
|
||||
}
|
||||
};
|
||||
|
||||
// After (using definitions)
|
||||
const apiDefinitions = require('./../api/definitions/index.js');
|
||||
this.inavAPI = this.buildAPIStructure(apiDefinitions);
|
||||
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**One Rule: Edit only `js/transpiler/api/definitions/*.js`**
|
||||
|
||||
Everything else updates automatically (except `codegen.js` which requires manual updates for new operations).
|
||||
|
||||
This ensures:
|
||||
- ✅ Single source of truth
|
||||
- ✅ No duplication
|
||||
- ✅ Easy maintenance
|
||||
- ✅ Fewer bugs
|
||||
- ✅ Automatic validation
|
||||
- ✅ Automatic type generation
|
||||
Reference in New Issue
Block a user