1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-25 17:25:13 +03:00

YAML storage (#7071)

YAML storage
This commit is contained in:
Raphael Coeffic 2019-11-12 14:50:05 +01:00 committed by Bertrand Songis
parent bb2ca31dad
commit 8b4d2b698d
69 changed files with 5577 additions and 425 deletions

View file

@ -129,27 +129,45 @@ endforeach()
set(SRC ${SRC} debug.cpp)
if(${EEPROM} STREQUAL SDCARD)
set(SRC ${SRC} storage/storage_common.cpp storage/sdcard_raw.cpp)
elseif(${EEPROM} STREQUAL EEPROM_RLC)
set(SRC ${SRC} storage/storage_common.cpp storage/eeprom_common.cpp storage/eeprom_rlc.cpp)
add_definitions(-DEEPROM -DEEPROM_RLC)
else()
set(SRC ${SRC} storage/storage_common.cpp storage/eeprom_common.cpp storage/eeprom_raw.cpp)
add_definitions(-DEEPROM -DEEPROM_RAW)
endif()
include(storage/conversions/CMakeLists.txt)
add_definitions(-DFLAVOUR="${FLAVOUR}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/bitmaps/${GUI_DIR})
add_subdirectory(lua)
include(gui/CMakeLists.txt)
set(SRC ${SRC} storage/storage_common.cpp)
if(${STORAGE} STREQUAL SDCARD)
set(SRC ${SRC} storage/modelslist.cpp storage/sdcard_common.cpp)
if(${STORAGE_FORMAT} STREQUAL BIN)
set(SRC ${SRC} storage/sdcard_raw.cpp)
add_definitions(-DSDCARD_RAW)
elseif(${STORAGE_FORMAT} STREQUAL YAML)
set(SRC ${SRC} storage/sdcard_yaml.cpp)
add_definitions(-DSDCARD_YAML)
include(storage/yaml/CMakeLists.txt)
#add_subdirectory(storage/yaml)
endif()
elseif(${STORAGE} STREQUAL EEPROM)
set(SRC ${SRC} storage/eeprom_common.cpp)
add_definitions(-DEEPROM)
if(${STORAGE_FORMAT} STREQUAL RLC)
set(SRC ${SRC} storage/eeprom_rlc.cpp)
add_definitions(-DEEPROM_RLC)
elseif(${STORAGE_FORMAT} STREQUAL RAW)
set(SRC ${SRC} storage/eeprom_raw.cpp)
add_definitions(-DEEPROM_RAW)
else()
set(SRC ${SRC} storage/eeprom_none.cpp)
add_definitions(-DEEPROM_NONE)
endif()
endif()
include(storage/conversions/CMakeLists.txt)
add_subdirectory(lua)
if(RAMBACKUP)
add_definitions(-DRAMBACKUP)
set(SRC ${SRC} storage/rambackup.cpp storage/rlc.cpp)

View file

@ -22,6 +22,7 @@
#define _DATACONSTANTS_H_
#include "board.h"
#include "storage/yaml/yaml_defs.h"
#define NUM_STICKS 4
@ -384,7 +385,7 @@ enum PotsWarnMode {
enum SwitchSources {
SWSRC_NONE = 0,
SWSRC_FIRST_SWITCH,
SWSRC_FIRST_SWITCH SKIP,
#if defined(STORAGE_SWITCH_A)
SWSRC_SA0 = SWSRC_FIRST_SWITCH,
@ -504,18 +505,18 @@ enum SwitchSources {
SWSRC_AIL,
SWSRC_GEA,
SWSRC_TRN,
SWSRC_TRAINER = SWSRC_TRN,
SWSRC_LAST_SWITCH = SWSRC_TRN,
SWSRC_TRAINER SKIP = SWSRC_TRN,
SWSRC_LAST_SWITCH SKIP = SWSRC_TRN,
#else
SWSRC_LAST_SWITCH = SWSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES_POSITIONS - 1,
SWSRC_LAST_SWITCH SKIP = SWSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES_POSITIONS - 1,
#endif
#if NUM_XPOTS > 0
SWSRC_FIRST_MULTIPOS_SWITCH,
SWSRC_LAST_MULTIPOS_SWITCH = SWSRC_FIRST_MULTIPOS_SWITCH + (NUM_XPOTS * XPOTS_MULTIPOS_COUNT) - 1,
SWSRC_FIRST_MULTIPOS_SWITCH SKIP,
SWSRC_LAST_MULTIPOS_SWITCH SKIP = SWSRC_FIRST_MULTIPOS_SWITCH + (NUM_XPOTS * XPOTS_MULTIPOS_COUNT) - 1,
#endif
SWSRC_FIRST_TRIM,
SWSRC_FIRST_TRIM SKIP,
SWSRC_TrimRudLeft = SWSRC_FIRST_TRIM,
SWSRC_TrimRudRight,
SWSRC_TrimEleDown,
@ -539,22 +540,22 @@ enum SwitchSources {
SWSRC_REa,
#endif
SWSRC_FIRST_LOGICAL_SWITCH,
SWSRC_FIRST_LOGICAL_SWITCH SKIP,
SWSRC_SW1 = SWSRC_FIRST_LOGICAL_SWITCH,
SWSRC_SW2,
// ...
SWSRC_LAST_LOGICAL_SWITCH = SWSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
SWSRC_LAST_LOGICAL_SWITCH SKIP = SWSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
SWSRC_ON,
SWSRC_ONE,
SWSRC_FIRST_FLIGHT_MODE,
SWSRC_LAST_FLIGHT_MODE = SWSRC_FIRST_FLIGHT_MODE+MAX_FLIGHT_MODES-1,
SWSRC_FIRST_FLIGHT_MODE SKIP,
SWSRC_LAST_FLIGHT_MODE SKIP = SWSRC_FIRST_FLIGHT_MODE+MAX_FLIGHT_MODES-1,
SWSRC_TELEMETRY_STREAMING,
SWSRC_FIRST_SENSOR,
SWSRC_LAST_SENSOR = SWSRC_FIRST_SENSOR+MAX_TELEMETRY_SENSORS-1,
SWSRC_FIRST_SENSOR SKIP,
SWSRC_LAST_SENSOR SKIP = SWSRC_FIRST_SENSOR+MAX_TELEMETRY_SENSORS-1,
SWSRC_RADIO_ACTIVITY,
@ -562,20 +563,20 @@ enum SwitchSources {
SWSRC_LATENCY_TOGGLE,
#endif
SWSRC_COUNT,
SWSRC_COUNT SKIP,
SWSRC_OFF = -SWSRC_ON,
SWSRC_LAST = SWSRC_COUNT-1,
SWSRC_FIRST = -SWSRC_LAST,
SWSRC_LAST SKIP = SWSRC_COUNT-1,
SWSRC_FIRST SKIP = -SWSRC_LAST,
SWSRC_LAST_IN_LOGICAL_SWITCHES = SWSRC_COUNT-1,
SWSRC_LAST_IN_MIXES = SWSRC_COUNT-1,
SWSRC_LAST_IN_LOGICAL_SWITCHES SKIP = SWSRC_COUNT-1,
SWSRC_LAST_IN_MIXES SKIP = SWSRC_COUNT-1,
SWSRC_FIRST_IN_LOGICAL_SWITCHES = -SWSRC_LAST_IN_LOGICAL_SWITCHES,
SWSRC_FIRST_IN_MIXES = -SWSRC_LAST_IN_MIXES,
SWSRC_FIRST_IN_LOGICAL_SWITCHES SKIP = -SWSRC_LAST_IN_LOGICAL_SWITCHES,
SWSRC_FIRST_IN_MIXES SKIP = -SWSRC_LAST_IN_MIXES,
SWSRC_INVERT = SWSRC_COUNT+1,
SWSRC_INVERT SKIP = SWSRC_COUNT+1,
};
#if NUM_SWITCHES >= 8
@ -589,22 +590,22 @@ enum SwitchSources {
enum MixSources {
MIXSRC_NONE,
MIXSRC_FIRST_INPUT, LUA_EXPORT_MULTIPLE("input", "Input [I%d]", MAX_INPUTS)
MIXSRC_LAST_INPUT = MIXSRC_FIRST_INPUT+MAX_INPUTS-1,
MIXSRC_FIRST_INPUT SKIP, LUA_EXPORT_MULTIPLE("input", "Input [I%d]", MAX_INPUTS)
MIXSRC_LAST_INPUT SKIP = MIXSRC_FIRST_INPUT+MAX_INPUTS-1,
#if defined(LUA_INPUTS)
MIXSRC_FIRST_LUA, LUA_EXPORT_MULTIPLE("lua", "Lua mix output %d", MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)
MIXSRC_LAST_LUA = MIXSRC_FIRST_LUA+(MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)-1,
MIXSRC_FIRST_LUA SKIP, LUA_EXPORT_MULTIPLE("lua", "Lua mix output %d", MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)
MIXSRC_LAST_LUA SKIP = MIXSRC_FIRST_LUA+(MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)-1,
#endif
MIXSRC_FIRST_STICK,
MIXSRC_FIRST_STICK SKIP,
MIXSRC_Rud = MIXSRC_FIRST_STICK, LUA_EXPORT("rud", "Rudder")
MIXSRC_Ele, LUA_EXPORT("ele", "Elevator")
MIXSRC_Thr, LUA_EXPORT("thr", "Throttle")
MIXSRC_Ail, LUA_EXPORT("ail", "Aileron")
MIXSRC_LAST_STICK = MIXSRC_Ail,
MIXSRC_FIRST_POT,
MIXSRC_LAST_STICK SKIP = MIXSRC_Ail,
MIXSRC_FIRST_POT SKIP,
#if defined(PCBHORUS)
MIXSRC_S1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer S1")
MIXSRC_6POS, LUA_EXPORT("6pos", "Multipos Switch")
@ -613,7 +614,7 @@ enum MixSources {
MIXSRC_EXT1, LUA_EXPORT("ext1", "Ext 1")
MIXSRC_EXT2, LUA_EXPORT("ext2", "Ext 2")
#endif
MIXSRC_FIRST_SLIDER,
MIXSRC_FIRST_SLIDER SKIP,
#if defined(PCBX12S)
MIXSRC_S3 = MIXSRC_FIRST_SLIDER, LUA_EXPORT("s3", "Slider S3")
MIXSRC_S4, LUA_EXPORT("s4", "Slider S4")
@ -623,7 +624,7 @@ enum MixSources {
MIXSRC_LS = MIXSRC_FIRST_SLIDER, LUA_EXPORT("ls", "Left slider")
MIXSRC_RS, LUA_EXPORT("rs", "Right slider")
#endif
MIXSRC_LAST_POT = MIXSRC_RS,
MIXSRC_LAST_POT SKIP = MIXSRC_RS,
#elif defined(PCBX9E)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
@ -634,27 +635,27 @@ enum MixSources {
MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider")
MIXSRC_SLIDER3, LUA_EXPORT("lcs", "Left center slider (X9E only)")
MIXSRC_SLIDER4, LUA_EXPORT("rcs", "Right center slider (X9E only)")
MIXSRC_LAST_POT = MIXSRC_SLIDER4,
MIXSRC_LAST_POT SKIP = MIXSRC_SLIDER4,
#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBNV14)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_LAST_POT = MIXSRC_POT2,
MIXSRC_LAST_POT SKIP = MIXSRC_POT2,
#elif defined(PCBX9LITE)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_LAST_POT = MIXSRC_POT1,
MIXSRC_LAST_POT SKIP = MIXSRC_POT1,
#elif defined(PCBTARANIS)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_POT3, LUA_EXPORT("s3", "Potentiometer 3")
MIXSRC_FIRST_SLIDER,
MIXSRC_FIRST_SLIDER SKIP,
MIXSRC_SLIDER1 = MIXSRC_FIRST_SLIDER, LUA_EXPORT("ls", "Left slider")
MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider")
MIXSRC_LAST_POT = MIXSRC_SLIDER2,
MIXSRC_LAST_POT SKIP = MIXSRC_SLIDER2,
#else
MIXSRC_P1 = MIXSRC_FIRST_POT,
MIXSRC_P2,
MIXSRC_P3,
MIXSRC_LAST_POT = MIXSRC_P3,
MIXSRC_LAST_POT SKIP = MIXSRC_P3,
#endif
#if defined(PCBHORUS)
@ -669,13 +670,13 @@ enum MixSources {
MIXSRC_MAX,
MIXSRC_FIRST_HELI,
MIXSRC_FIRST_HELI SKIP,
MIXSRC_CYC1 = MIXSRC_FIRST_HELI, LUA_EXPORT("cyc1", "Cyclic 1")
MIXSRC_CYC2, LUA_EXPORT("cyc2", "Cyclic 2")
MIXSRC_CYC3, LUA_EXPORT("cyc3", "Cyclic 3")
MIXSRC_LAST_HELI = MIXSRC_CYC3,
MIXSRC_LAST_HELI SKIP = MIXSRC_CYC3,
MIXSRC_FIRST_TRIM,
MIXSRC_FIRST_TRIM SKIP,
MIXSRC_TrimRud = MIXSRC_FIRST_TRIM, LUA_EXPORT("trim-rud", "Rudder trim")
MIXSRC_TrimEle, LUA_EXPORT("trim-ele", "Elevator trim")
MIXSRC_TrimThr, LUA_EXPORT("trim-thr", "Throttle trim")
@ -683,12 +684,12 @@ enum MixSources {
#if defined(PCBHORUS)
MIXSRC_TrimT5, LUA_EXPORT("trim-t5", "Aux trim T5")
MIXSRC_TrimT6, LUA_EXPORT("trim-t6", "Aux trim T6")
MIXSRC_LAST_TRIM = MIXSRC_TrimT6,
MIXSRC_LAST_TRIM SKIP = MIXSRC_TrimT6,
#else
MIXSRC_LAST_TRIM = MIXSRC_TrimAil,
MIXSRC_LAST_TRIM SKIP = MIXSRC_TrimAil,
#endif
MIXSRC_FIRST_SWITCH,
MIXSRC_FIRST_SWITCH SKIP,
#if defined(HARDWARE_SWITCH_A)
MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A")
@ -749,14 +750,14 @@ enum MixSources {
MIXSRC_GEA,
MIXSRC_TRN,
#endif
MIXSRC_FIRST_LOGICAL_SWITCH,
MIXSRC_FIRST_LOGICAL_SWITCH SKIP,
MIXSRC_SW1 = MIXSRC_FIRST_LOGICAL_SWITCH, LUA_EXPORT_MULTIPLE("ls", "Logical switch L%d", MAX_LOGICAL_SWITCHES)
MIXSRC_LAST_LOGICAL_SWITCH = MIXSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
MIXSRC_LAST_LOGICAL_SWITCH SKIP = MIXSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
MIXSRC_FIRST_TRAINER, LUA_EXPORT_MULTIPLE("trn", "Trainer input %d", MAX_TRAINER_CHANNELS)
MIXSRC_LAST_TRAINER = MIXSRC_FIRST_TRAINER+MAX_TRAINER_CHANNELS-1,
MIXSRC_FIRST_TRAINER SKIP, LUA_EXPORT_MULTIPLE("trn", "Trainer input %d", MAX_TRAINER_CHANNELS)
MIXSRC_LAST_TRAINER SKIP = MIXSRC_FIRST_TRAINER+MAX_TRAINER_CHANNELS-1,
MIXSRC_FIRST_CH,
MIXSRC_FIRST_CH SKIP,
MIXSRC_CH1 = MIXSRC_FIRST_CH, LUA_EXPORT_MULTIPLE("ch", "Channel CH%d", MAX_OUTPUT_CHANNELS)
MIXSRC_CH2,
MIXSRC_CH3,
@ -773,32 +774,32 @@ enum MixSources {
MIXSRC_CH14,
MIXSRC_CH15,
MIXSRC_CH16,
MIXSRC_LAST_CH = MIXSRC_CH1+MAX_OUTPUT_CHANNELS-1,
MIXSRC_LAST_CH SKIP = MIXSRC_CH1+MAX_OUTPUT_CHANNELS-1,
MIXSRC_FIRST_GVAR,
MIXSRC_FIRST_GVAR SKIP,
MIXSRC_GVAR1 = MIXSRC_FIRST_GVAR, LUA_EXPORT_MULTIPLE("gvar", "Global variable %d", MAX_GVARS)
MIXSRC_LAST_GVAR = MIXSRC_FIRST_GVAR+MAX_GVARS-1,
MIXSRC_LAST_GVAR SKIP = MIXSRC_FIRST_GVAR+MAX_GVARS-1,
MIXSRC_TX_VOLTAGE, LUA_EXPORT("tx-voltage", "Transmitter battery voltage [volts]")
MIXSRC_TX_TIME, LUA_EXPORT("clock", "RTC clock [minutes from midnight]")
#if defined(INTERNAL_GPS)
MIXSRC_TX_GPS,
MIXSRC_FIRST_RESERVE,
MIXSRC_FIRST_RESERVE SKIP,
#else
MIXSRC_FIRST_RESERVE,
MIXSRC_RESERVE2,
MIXSRC_FIRST_RESERVE SKIP,
MIXSRC_RESERVE2 SKIP,
#endif
MIXSRC_RESERVE3,
MIXSRC_RESERVE4,
MIXSRC_LAST_RESERVE,
MIXSRC_FIRST_TIMER,
MIXSRC_RESERVE3 SKIP,
MIXSRC_RESERVE4 SKIP,
MIXSRC_LAST_RESERVE SKIP,
MIXSRC_FIRST_TIMER SKIP,
MIXSRC_TIMER1 = MIXSRC_FIRST_TIMER, LUA_EXPORT("timer1", "Timer 1 value [seconds]")
MIXSRC_TIMER2, LUA_EXPORT("timer2", "Timer 2 value [seconds]")
MIXSRC_TIMER3, LUA_EXPORT("timer3", "Timer 3 value [seconds]")
MIXSRC_LAST_TIMER = MIXSRC_TIMER3,
MIXSRC_LAST_TIMER SKIP = MIXSRC_TIMER3,
MIXSRC_FIRST_TELEM, LUA_EXPORT_MULTIPLE("telem", "Telemetry sensor %d", MAX_TELEMETRY_SENSORS)
MIXSRC_LAST_TELEM = MIXSRC_FIRST_TELEM+3*MAX_TELEMETRY_SENSORS-1
MIXSRC_FIRST_TELEM SKIP, LUA_EXPORT_MULTIPLE("telem", "Telemetry sensor %d", MAX_TELEMETRY_SENSORS)
MIXSRC_LAST_TELEM SKIP = MIXSRC_FIRST_TELEM+3*MAX_TELEMETRY_SENSORS-1
};
#if defined(__cplusplus)

View file

@ -25,6 +25,7 @@
#include "board.h"
#include "dataconstants.h"
#include "definitions.h"
#include "opentx_types.h"
#if defined(PCBTARANIS)
#define N_TARANIS_FIELD(x)
@ -54,6 +55,8 @@
#define NOBACKUP(...) __VA_ARGS__
#endif
#include "storage/yaml/yaml_defs.h"
/*
* Mixer structure
*/
@ -64,15 +67,15 @@ PACK(struct CurveRef {
});
PACK(struct MixData {
int16_t weight:11; // GV1=-1024, -GV1=1023
int16_t weight:11 CUST(in_read_weight,in_write_weight); // GV1=-1024, -GV1=1023
uint16_t destCh:5;
uint16_t srcRaw:10; // srcRaw=0 means not used
uint16_t srcRaw:10 CUST(r_mixSrcRaw,w_mixSrcRaw); // srcRaw=0 means not used
uint16_t carryTrim:1;
uint16_t mixWarn:2; // mixer warning
uint16_t mltpx:2; // multiplex method: 0 means +=, 1 means *=, 2 means :=
uint16_t spare:1;
uint16_t spare:1 SKIP;
int32_t offset:14;
int32_t swtch:9;
int32_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
uint32_t flightModes:9;
CurveRef curve;
uint8_t delayUp;
@ -89,13 +92,13 @@ PACK(struct MixData {
PACK(struct ExpoData {
uint16_t mode:2;
uint16_t scale:14;
uint16_t srcRaw:10;
uint16_t srcRaw:10 ENUM(MixSources);
int16_t carryTrim:6;
uint32_t chn:5;
int32_t swtch:9;
int32_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
uint32_t flightModes:9;
int32_t weight:8;
int32_t spare:1;
int32_t weight:8 CUST(in_read_weight,in_write_weight);
int32_t spare:1 SKIP;
NOBACKUP(char name[LEN_EXPOMIX_NAME]);
int8_t offset;
CurveRef curve;
@ -112,7 +115,7 @@ PACK(struct LimitData {
int16_t offset:11;
uint16_t symetrical:1;
uint16_t revert:1;
uint16_t spare:3;
uint16_t spare:3 SKIP;
int8_t curve;
NOBACKUP(char name[LEN_CHANNEL_NAME]);
});
@ -122,12 +125,12 @@ PACK(struct LimitData {
*/
PACK(struct LogicalSwitchData {
uint8_t func;
uint8_t func ENUM(LogicalSwitchesFunctions);
int32_t v1:10;
int32_t v3:10;
int32_t andsw:9; // TODO rename to xswtch
uint32_t andswtype:1; // TODO rename to xswtchType (AND / OR)
uint32_t spare:2; // anything else needed?
uint32_t spare:2 SKIP; // anything else needed?
int16_t v2;
uint8_t delay;
uint8_t duration;
@ -145,8 +148,8 @@ PACK(struct LogicalSwitchData {
#endif
PACK(struct CustomFunctionData {
int16_t swtch:9;
uint16_t func:7;
int16_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
uint16_t func:7 ENUM(Functions);
PACK(union {
NOBACKUP(PACK(struct {
char name[LEN_FUNCTION_NAME];
@ -156,14 +159,14 @@ PACK(struct CustomFunctionData {
int16_t val;
uint8_t mode;
uint8_t param;
NOBACKUP(CFN_SPARE_TYPE spare);
NOBACKUP(CFN_SPARE_TYPE spare SKIP);
}) all;
NOBACKUP(PACK(struct {
int32_t val1;
NOBACKUP(CFN_SPARE_TYPE val2);
NOBACKUP(CFN_SPARE_TYPE val2 SKIP);
}) clear);
});
}) NAME(fp) FUNC(select_custom_fn);
uint8_t active;
bool isEmpty() const
@ -184,11 +187,11 @@ PACK(struct trim_t {
PACK(struct FlightModeData {
trim_t trim[NUM_TRIMS];
NOBACKUP(char name[LEN_FLIGHT_MODE_NAME]);
int16_t swtch:9; // swtch of phase[0] is not used
int16_t spare:7;
int16_t swtch:9 ENUM(SwitchSources) CUST(r_swtchSrc,w_swtchSrc); // swtch of phase[0] is not used
int16_t spare:7 SKIP;
uint8_t fadeIn;
uint8_t fadeOut;
gvar_t gvars[MAX_GVARS];
gvar_t gvars[MAX_GVARS] FUNC(gvar_is_active);
});
/*
@ -213,7 +216,7 @@ PACK(struct GVarData {
uint32_t popup:1;
uint32_t prec:1;
uint32_t unit:2;
uint32_t spare:4;
uint32_t spare:4 SKIP;
});
/*
@ -251,7 +254,7 @@ PACK(struct SwashRingData {
union ScriptDataInput {
int16_t value;
source_t source;
};
} FUNC(select_script_input);
PACK(struct ScriptData {
char file[LEN_SCRIPT_FILENAME];
@ -268,10 +271,10 @@ PACK(struct RssiAlarmData {
#if defined (PCBNV14)
uint8_t flysky_telemetry:1; // if set for FlySky receivers use native RSSI values instead of rescaled ones
#else
int8_t spare:1;
int8_t spare:1 SKIP;
#endif
int8_t warning:6;
int8_t spare2:2;
int8_t spare2:2 SKIP;
int8_t critical:6;
inline int8_t getWarningRssi() {return 45 + warning;}
inline int8_t getCriticalRssi() {return 42 + critical;}
@ -326,7 +329,7 @@ PACK(struct TelemetrySensor {
union {
uint16_t id; // data identifier, for FrSky we can reuse existing ones. Source unit is derived from type.
NOBACKUP(uint16_t persistentValue);
};
} NAME(id1) FUNC(select_id1);
union {
PACK(struct {
uint8_t physID:5;
@ -334,11 +337,11 @@ PACK(struct TelemetrySensor {
}) frskyInstance;
uint8_t instance;
NOBACKUP(uint8_t formula);
};
} NAME(id2) FUNC(select_id2);
char label[TELEM_LABEL_LEN]; // user defined label
uint8_t subId;
uint8_t type:1; // 0=custom / 1=calculated // user can choose what unit to display each value in
uint8_t spare1:1;
uint8_t spare1:1 SKIP;
uint8_t unit:6;
uint8_t prec:2;
uint8_t autoOffset:1;
@ -346,7 +349,7 @@ PACK(struct TelemetrySensor {
uint8_t logs:1;
uint8_t persistent:1;
uint8_t onlyPositive:1;
uint8_t spare2:1;
uint8_t spare2:1 SKIP;
union {
NOBACKUP(PACK(struct {
uint16_t ratio;
@ -355,22 +358,22 @@ PACK(struct TelemetrySensor {
NOBACKUP(PACK(struct {
uint8_t source;
uint8_t index;
uint16_t spare;
uint16_t spare SKIP;
}) cell);
NOBACKUP(PACK(struct {
int8_t sources[4];
}) calc);
NOBACKUP(PACK(struct {
uint8_t source;
uint8_t spare[3];
uint8_t spare[3] SKIP;
}) consumption);
NOBACKUP(PACK(struct {
uint8_t gps;
uint8_t alt;
uint16_t spare;
uint16_t spare SKIP;
}) dist);
uint32_t param;
};
} NAME(cfg) FUNC(select_sensor_cfg);
NOBACKUP(
void init(const char *label, uint8_t unit=UNIT_RAW, uint8_t prec=0);
void init(uint16_t id);
@ -403,13 +406,13 @@ PACK(struct TelemetrySensor {
PACK(struct TrainerModuleData {
uint8_t mode:3;
uint8_t spare1:5;
uint8_t spare1:5 SKIP;
uint8_t channelsStart;
int8_t channelsCount; // 0=8 channels
int8_t frameLength;
int8_t delay:6;
uint8_t pulsePol:1;
uint8_t spare2:1;
uint8_t spare2:1 SKIP;
});
/*
@ -419,7 +422,7 @@ PACK(struct TrainerModuleData {
// Only used in case switch and if statements as "virtual" protocol
#define MM_RF_CUSTOM_SELECTED 0xff
PACK(struct ModuleData {
uint8_t type:4;
uint8_t type:4 ENUM(ModuleType);
// TODO some refactoring is needed, rfProtocol is only used by DSM2 and MULTI, it could be merged with subType
int8_t rfProtocol:4;
uint8_t channelsStart;
@ -438,7 +441,7 @@ PACK(struct ModuleData {
} ppm);
NOBACKUP(struct {
uint8_t rfProtocolExtra:2;
uint8_t spare1:3;
uint8_t spare1:3 SKIP;
uint8_t customProto:1;
uint8_t autoBindMode:1;
uint8_t lowPowerMode:1;
@ -446,16 +449,16 @@ PACK(struct ModuleData {
} multi);
NOBACKUP(struct {
uint8_t power:2; // 0=10 mW, 1=100 mW, 2=500 mW, 3=1W
uint8_t spare1:2;
uint8_t spare1:2 SKIP;
uint8_t receiverTelemetryOff:1; // false = receiver telem enabled
uint8_t receiverHigherChannels:1; // false = pwm out 1-8, true 9-16
int8_t antennaMode:2;
uint8_t spare2;
uint8_t spare2 SKIP;
} pxx);
NOBACKUP(struct {
uint8_t spare1:6;
uint8_t spare1:6 SKIP;
uint8_t noninverted:1;
uint8_t spare2:1;
uint8_t spare2:1 SKIP;
int8_t refreshRate; // definition as framelength for ppm (* 5 + 225 = time in 1/10 ms)
} sbus);
NOBACKUP(PACK(struct {
@ -469,7 +472,7 @@ PACK(struct ModuleData {
uint8_t rx_freq[2];
} flysky);
#endif
};
} NAME(mod) FUNC(select_mod_type);
// Helper functions to set both of the rfProto protocol at the same time
NOBACKUP(inline uint8_t getMultiProtocol(bool returnCustom) {
@ -589,9 +592,9 @@ PACK(struct ModelData {
int8_t points[MAX_CURVE_POINTS];
LogicalSwitchData logicalSw[MAX_LOGICAL_SWITCHES];
CustomFunctionData customFn[MAX_SPECIAL_FUNCTIONS];
CustomFunctionData customFn[MAX_SPECIAL_FUNCTIONS] FUNC(cfn_is_active);
SwashRingData swashR;
FlightModeData flightModeData[MAX_FLIGHT_MODES];
FlightModeData flightModeData[MAX_FLIGHT_MODES] FUNC(fmd_is_active);
NOBACKUP(uint8_t thrTraceSrc);
@ -606,7 +609,7 @@ PACK(struct ModelData {
NOBACKUP(RssiAlarmData rssiAlarms);
NOBACKUP(uint8_t spare1:6);
NOBACKUP(uint8_t spare1:6 SKIP);
NOBACKUP(uint8_t potsWarnMode:2);
ModuleData moduleData[NUM_MODULES];
@ -673,37 +676,37 @@ PACK(struct TrainerData {
#if defined(PCBHORUS) || defined(PCBNV14)
#define EXTRA_GENERAL_FIELDS \
NOBACKUP(uint8_t auxSerialMode); \
swconfig_t switchConfig; \
uint16_t potsConfig; /* two bits per pot */ \
uint8_t slidersConfig; /* 1 bit per slider */ \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
uint16_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */ \
uint8_t slidersConfig ARRAY(1,struct_sliderConfig,nullptr); /* 1 bit per slider */ \
NOBACKUP(char switchNames[STORAGE_NUM_SWITCHES][LEN_SWITCH_NAME]); \
NOBACKUP(char anaNames[NUM_STICKS + STORAGE_NUM_POTS + STORAGE_NUM_SLIDERS][LEN_ANA_NAME]); \
NOBACKUP(char currModelFilename[LEN_MODEL_FILENAME+1]); \
NOBACKUP(uint8_t spare5:1); \
NOBACKUP(uint8_t spare5:1 SKIP); \
NOBACKUP(uint8_t blOffBright:7); \
NOBACKUP(char bluetoothName[LEN_BLUETOOTH_NAME]);
#elif defined(PCBTARANIS) || defined(PCBNV14)
#if defined(STORAGE_BLUETOOTH)
#define BLUETOOTH_FIELDS \
uint8_t spare5; \
uint8_t spare5 SKIP; \
char bluetoothName[LEN_BLUETOOTH_NAME];
#else
#define BLUETOOTH_FIELDS
#endif
#define EXTRA_GENERAL_FIELDS \
uint8_t auxSerialMode:4; \
uint8_t slidersConfig:4; \
uint8_t potsConfig; /* two bits per pot */\
uint8_t slidersConfig:4 ARRAY(1,struct_sliderConfig,nullptr); \
uint8_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */\
uint8_t backlightColor; \
swarnstate_t switchUnlockStates; \
swconfig_t switchConfig; \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
char switchNames[STORAGE_NUM_SWITCHES][LEN_SWITCH_NAME]; \
char anaNames[NUM_STICKS+STORAGE_NUM_POTS+STORAGE_NUM_SLIDERS][LEN_ANA_NAME]; \
BLUETOOTH_FIELDS
#elif defined(PCBSKY9X)
#define EXTRA_GENERAL_FIELDS \
int8_t txCurrentCalibration; \
int8_t spare5; \
int8_t spare5 SKIP; \
uint8_t mAhWarn; \
uint16_t mAhUsed; \
int8_t temperatureCalib; \
@ -729,7 +732,7 @@ PACK(struct TrainerData {
#if defined(BUZZER)
#define BUZZER_FIELD int8_t buzzerMode:2 // -2=quiet, -1=only alarms, 0=no keys, 1=all (only used on AVR radios without audio hardware)
#else
#define BUZZER_FIELD int8_t spare4:2
#define BUZZER_FIELD int8_t spare4:2 SKIP
#endif
PACK(struct RadioData {
@ -744,7 +747,7 @@ PACK(struct RadioData {
uint8_t backlightMode:3;
int8_t antennaMode:2;
uint8_t disableRtcWarning:1;
int8_t spare1:2;
int8_t spare1:2 SKIP;
NOBACKUP(TrainerData trainer);
NOBACKUP(uint8_t view); // index of view in main screen
NOBACKUP(BUZZER_FIELD); /* 2bits */
@ -765,7 +768,7 @@ PACK(struct RadioData {
NOBACKUP(uint8_t templateSetup); // RETA order for receiver channels
NOBACKUP(int8_t PPM_Multiplier);
NOBACKUP(int8_t hapticLength);
N_HORUS_FIELD(N_TARANIS_FIELD(uint8_t spare2));
N_HORUS_FIELD(N_TARANIS_FIELD(uint8_t spare2 SKIP));
N_HORUS_FIELD(N_TARANIS_FIELD(uint8_t stickReverse));
NOBACKUP(int8_t beepLength:3);
NOBACKUP(int8_t hapticStrength:3);
@ -773,8 +776,8 @@ PACK(struct RadioData {
NOBACKUP(uint8_t unexpectedShutdown:1);
NOBACKUP(uint8_t speakerPitch);
NOBACKUP(int8_t speakerVolume);
NOBACKUP(int8_t vBatMin);
NOBACKUP(int8_t vBatMax);
NOBACKUP(int8_t vBatMin CUST(r_vbat_min,w_vbat_min));
NOBACKUP(int8_t vBatMax CUST(r_vbat_max,w_vbat_max));
NOBACKUP(uint8_t backlightBright);
NOBACKUP(uint32_t globalTimer);
@ -788,7 +791,7 @@ PACK(struct RadioData {
NOBACKUP(uint8_t disableRssiPoweroffAlarm:1);
NOBACKUP(uint8_t USBMode:2);
NOBACKUP(uint8_t jackMode:2);
NOBACKUP(uint8_t spare3:1);
NOBACKUP(uint8_t spare3:1 SKIP);
NOBACKUP(char ttsLanguage[2]);
NOBACKUP(int8_t beepVolume:4);
NOBACKUP(int8_t wavVolume:4);
@ -797,7 +800,7 @@ PACK(struct RadioData {
NOBACKUP(int8_t varioPitch);
NOBACKUP(int8_t varioRange);
NOBACKUP(int8_t varioRepeat);
CustomFunctionData customFn[MAX_SPECIAL_FUNCTIONS];
CustomFunctionData customFn[MAX_SPECIAL_FUNCTIONS] FUNC(cfn_is_active);
EXTRA_GENERAL_FIELDS
@ -880,8 +883,8 @@ static inline void check_struct()
CHKSIZE(SwashRingData, 8);
CHKSIZE(ModelHeader, 31);
CHKSIZE(CurveHeader, 4);
CHKSIZE(CustomScreenData, 610);
CHKSIZE(Topbar::PersistentData, 216);
CHKSIZE(CustomScreenData, 850);
CHKSIZE(Topbar::PersistentData, 300);
#elif defined(PCBNV14)
// TODO
#elif defined(PCBSKY9X)
@ -942,8 +945,8 @@ static inline void check_struct()
CHKSIZE(RadioData, 735);
CHKSIZE(ModelData, 5301);
#elif defined(PCBHORUS)
CHKSIZE(RadioData, 881);
CHKSIZE(ModelData, 9736);
CHKSIZE(RadioData, 901);
CHKSIZE(ModelData, 11020);
#endif
#undef CHKSIZE

View file

@ -41,8 +41,8 @@ class Layout1x1: public Layout
void create() override
{
Layout::create();
persistentData->options[0].boolValue = true;
persistentData->options[1].boolValue = true;
persistentData->options[0] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[1] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
}
unsigned int getZonesCount() const override
@ -53,11 +53,11 @@ class Layout1x1: public Layout
Zone getZone(unsigned int index) const override
{
Zone zone = { 10, 10, LCD_W - 2*10, LCD_H - 2*10 };
if (persistentData->options[0].boolValue) {
if (persistentData->options[0].value.boolValue) {
zone.y += MENU_HEADER_HEIGHT;
zone.h -= MENU_HEADER_HEIGHT;
}
if (persistentData->options[1].boolValue) {
if (persistentData->options[1].value.boolValue) {
zone.x += 35;
zone.w -= 2*35;
zone.h -= 35;
@ -72,11 +72,11 @@ class Layout1x1: public Layout
//{
// theme->drawBackground();
//
// if (persistentData->options[0].boolValue) {
// if (persistentData->options[0].value.boolValue) {
// drawTopBar();
// }
//
// if (persistentData->options[1].boolValue) {
// if (persistentData->options[1].value.boolValue) {
// // Sliders + Trims + Flight mode
// lcdDrawSizedText(LCD_W / 2 - getTextWidth(g_model.flightModeData[mixerCurrentFlightMode].name, sizeof(g_model.flightModeData[mixerCurrentFlightMode].name), ZCHAR | FONT(XS)) / 2,
// 232,

View file

@ -49,10 +49,10 @@ class Layout2P1: public Layout
void create() override
{
Layout::create();
persistentData->options[0].boolValue = true;
persistentData->options[1].boolValue = true;
persistentData->options[2].boolValue = true;
persistentData->options[3].boolValue = true;
persistentData->options[0] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[1] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[2] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[3] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
}
unsigned int getZonesCount() const override
@ -72,11 +72,11 @@ class Layout2P1: public Layout
//{
// theme->drawBackground();
//
// if (persistentData->options[0].boolValue) {
// if (persistentData->options[0].value.boolValue) {
// drawTopBar();
// }
//
// if (persistentData->options[1].boolValue) {
// if (persistentData->options[1].value.boolValue) {
// // Flight mode
// lcdDrawSizedText(LCD_W / 2 - getTextWidth(g_model.flightModeData[mixerCurrentFlightMode].name,
// sizeof(g_model.flightModeData[mixerCurrentFlightMode].name),
@ -86,12 +86,12 @@ class Layout2P1: public Layout
// sizeof(g_model.flightModeData[mixerCurrentFlightMode].name), ZCHAR | FONT(XS));
// }
//
// if (persistentData->options[2].boolValue) {
// if (persistentData->options[2].value.boolValue) {
// // Pots and rear sliders positions
// drawMainPots();
// }
//
// if (persistentData->options[3].boolValue) {
// if (persistentData->options[3].value.boolValue) {
// // Trims
// drawTrims(mixerCurrentFlightMode);
// }

View file

@ -40,7 +40,7 @@ class Layout2x1: public Layout
void create() override
{
Layout::create();
persistentData->options[0].boolValue = true;
persistentData->options[0] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
}
unsigned int getZonesCount() const override
@ -53,7 +53,7 @@ class Layout2x1: public Layout
Zone zone;
zone.w = (LCD_W-3*10) / 2;
zone.x = (index & 1) ? 20 + zone.w : 10;
if (persistentData->options[0].boolValue) {
if (persistentData->options[0].value.boolValue) {
zone.h = (LCD_H-MENU_HEADER_HEIGHT-2*10);
zone.y = MENU_HEADER_HEIGHT + 10;
}
@ -71,7 +71,7 @@ class Layout2x1: public Layout
//{
// theme->drawBackground();
//
// if (persistentData->options[0].boolValue) {
// if (persistentData->options[0].value.boolValue) {
// drawTopBar();
// }
//

View file

@ -40,7 +40,7 @@ class Layout2x2: public Layout
void create() override
{
Layout::create();
persistentData->options[0].boolValue = true;
persistentData->options[0] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
}
unsigned int getZonesCount() const override
@ -53,7 +53,7 @@ class Layout2x2: public Layout
Zone zone;
zone.w = (LCD_W-3*10) / 2;
zone.x = (index & 1) ? 20 + zone.w : 10;
if (persistentData->options[0].boolValue) {
if (persistentData->options[0].value.boolValue) {
zone.h = (LCD_H-MENU_HEADER_HEIGHT-3*10) / 2;
zone.y = MENU_HEADER_HEIGHT + 10;
}
@ -74,7 +74,7 @@ class Layout2x2: public Layout
//{
// theme->drawBackground();
//
// if (persistentData->options[0].boolValue) {
// if (persistentData->options[0].value.boolValue) {
// drawTopBar();
// }
//

View file

@ -47,14 +47,14 @@ class Layout2x4: public Layout
void create() override
{
Layout::create();
persistentData->options[0].boolValue = true;
persistentData->options[1].boolValue = true;
persistentData->options[2].boolValue = true;
persistentData->options[3].boolValue = true;
persistentData->options[4].boolValue = true;
persistentData->options[5].unsignedValue = RGB(77, 112, 203);
persistentData->options[6].boolValue = false;
persistentData->options[7].unsignedValue = RGB(77, 112, 203);
persistentData->options[0] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[1] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[2] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[3] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[4] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[5] = ZoneOptionValueTyped { ZOV_Unsigned, OPTION_VALUE_UNSIGNED( RGB(77,112,203)) };
persistentData->options[6] = ZoneOptionValueTyped { ZOV_Bool, OPTION_VALUE_BOOL(true) };
persistentData->options[7] = ZoneOptionValueTyped { ZOV_Unsigned, OPTION_VALUE_UNSIGNED( RGB(77,112,203)) };
}
unsigned int getZonesCount() const override
@ -79,11 +79,11 @@ class Layout2x4: public Layout
//{
// theme->drawBackground();
//
// if (persistentData->options[0].boolValue) {
// if (persistentData->options[0].value.boolValue) {
// drawTopBar();
// }
//
// if (persistentData->options[1].boolValue) {
// if (persistentData->options[1].value.boolValue) {
// // Flight mode
// lcdDrawSizedText(LCD_W / 2 - getTextWidth(g_model.flightModeData[mixerCurrentFlightMode].name,
// sizeof(g_model.flightModeData[mixerCurrentFlightMode].name),
@ -93,23 +93,23 @@ class Layout2x4: public Layout
// sizeof(g_model.flightModeData[mixerCurrentFlightMode].name), ZCHAR | FONT(XS));
// }
//
// if (persistentData->options[2].boolValue) {
// if (persistentData->options[2].value.boolValue) {
// // Pots and rear sliders positions
// drawMainPots();
// }
//
// if (persistentData->options[3].boolValue) {
// if (persistentData->options[3].value.boolValue) {
// // Trims
// drawTrims(mixerCurrentFlightMode);
// }
//
// if (persistentData->options[4].boolValue) {
// lcdSetColor(persistentData->options[5].unsignedValue);
// if (persistentData->options[4].value.boolValue) {
// lcdSetColor(persistentData->options[5].value.unsignedValue);
// lcdDrawSolidFilledRect(50, 50, 180, 170, CUSTOM_COLOR);
// }
//
// if (persistentData->options[6].boolValue) {
// lcdSetColor(persistentData->options[7].unsignedValue);
// if (persistentData->options[6].value.boolValue) {
// lcdSetColor(persistentData->options[7].value.unsignedValue);
// lcdDrawSolidFilledRect(250, 50, 180, 170, CUSTOM_COLOR);
// }
//

View file

@ -53,7 +53,8 @@ void ThemeBase::init() const
int i = 0;
for (const ZoneOption * option = options; option->name; option++, i++) {
// TODO compiler bug? The CPU freezes ... g_eeGeneral.themeData.options[i] = &option->deflt;
memcpy(&g_eeGeneral.themeData.options[i], &option->deflt, sizeof(ZoneOptionValue));
memcpy(&g_eeGeneral.themeData.options[i].value, &option->deflt, sizeof(ZoneOptionValue));
g_eeGeneral.themeData.options[i].type = zoneValueEnumFromType(option->type);
}
}
}
@ -70,7 +71,7 @@ void ThemeBase::load() const
ZoneOptionValue * ThemeBase::getOptionValue(unsigned int index) const
{
return &g_eeGeneral.themeData.options[index];
return &g_eeGeneral.themeData.options[index].value;
}
const char * ThemeBase::getFilePath(const char * filename) const

View file

@ -34,11 +34,16 @@ class PageTab;
class ThemeBase;
void registerTheme(ThemeBase * theme);
// YAML_GENERATOR defs
#if !defined(USE_IDX)
#define USE_IDX
#endif
class ThemeBase: public Theme
{
public:
struct PersistentData {
ZoneOptionValue options[MAX_THEME_OPTIONS];
ZoneOptionValueTyped options[MAX_THEME_OPTIONS] USE_IDX;
};
ThemeBase(const char * name, const ZoneOption * options = nullptr):
@ -79,7 +84,7 @@ class ThemeBase: public Theme
virtual void drawMenuHeader(BitmapBuffer * dc, std::vector<PageTab *> & tabs, uint8_t currentIndex) const = 0;
virtual void drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const;
virtual void drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const override;
// virtual void drawProgressBar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t w, coord_t h, int value) const = 0;
void drawCheckBox(BitmapBuffer * dc, bool checked, coord_t x, coord_t y, bool focus) const override;

View file

@ -337,7 +337,7 @@ class FlyskyTheme: public ThemeBase
dc->drawBitmap(0, 0, backgroundBitmap);
}
else {
lcdSetColor(g_eeGeneral.themeData.options[0].unsignedValue);
lcdSetColor(g_eeGeneral.themeData.options[0].value.unsignedValue);
dc->drawSolidFilledRect(0, 0, LCD_W, LCD_H, CUSTOM_COLOR);
}
}

View file

@ -287,8 +287,8 @@ class FrskyTheme: public ThemeBase
{
TRACE("TODO THEME::UPDATE()");
#if 0
uint32_t color = g_eeGeneral.themeData.options[1].unsignedValue;
uint32_t bg_color = UNEXPECTED_SHUTDOWN() ? WHITE : g_eeGeneral.themeData.options[0].unsignedValue;
uint32_t color = g_eeGeneral.themeData.options[1].value.unsignedValue;
uint32_t bg_color = UNEXPECTED_SHUTDOWN() ? WHITE : g_eeGeneral.themeData.options[0].value.unsignedValue;
lcdColorTable[DEFAULT_BGCOLOR_INDEX] = bg_color;
lcdColorTable[FOCUS_BGCOLOR_INDEX] = color;
@ -316,7 +316,7 @@ class FrskyTheme: public ThemeBase
dc->drawBitmap(0, 0, backgroundBitmap);
}
else {
lcdSetColor(g_eeGeneral.themeData.options[0].unsignedValue);
lcdSetColor(g_eeGeneral.themeData.options[0].value.unsignedValue);
dc->drawSolidFilledRect(0, 0, LCD_W, LCD_H, CUSTOM_COLOR);
}
}

View file

@ -24,15 +24,21 @@
#include <list>
#include <string.h>
#include "zone.h"
#include "debug.h"
#define MAX_WIDGET_OPTIONS 5
// YAML_GENERATOR defs
#if !defined(USE_IDX)
#define USE_IDX
#endif
class WidgetFactory;
class Widget
{
public:
struct PersistentData {
ZoneOptionValue options[MAX_WIDGET_OPTIONS];
ZoneOptionValueTyped options[MAX_WIDGET_OPTIONS] USE_IDX;
};
Widget(const WidgetFactory * factory, const Zone & zone, PersistentData * persistentData):
@ -64,7 +70,7 @@ class Widget
inline ZoneOptionValue * getOptionValue(unsigned int index) const
{
return &persistentData->options[index];
return &persistentData->options[index].value;
}
virtual void refresh() = 0;
@ -109,7 +115,8 @@ class WidgetFactory
for (const ZoneOption * option = options; option->name; option++) {
TRACE("WidgetFactory::initPersistentData() setting option '%s'", option->name);
// TODO compiler bug? The CPU freezes ... persistentData->options[i++] = option->deflt;
memcpy(&persistentData->options[i++], &option->deflt, sizeof(ZoneOptionValue));
memcpy(&persistentData->options[i++].value, &option->deflt, sizeof(ZoneOptionValue));
persistentData->options[i++].type = zoneValueEnumFromType(option->type);
}
}
}

View file

@ -43,10 +43,10 @@ const ZoneOption GaugeWidget::options[] = {
void GaugeWidget::refresh()
{
mixsrc_t index = persistentData->options[0].unsignedValue;
int32_t min = persistentData->options[1].signedValue;
int32_t max = persistentData->options[2].signedValue;
uint16_t color = persistentData->options[3].unsignedValue;
mixsrc_t index = persistentData->options[0].value.unsignedValue;
int32_t min = persistentData->options[1].value.signedValue;
int32_t max = persistentData->options[2].value.signedValue;
uint16_t color = persistentData->options[3].value.unsignedValue;
int32_t value = getValue(index);
int32_t value_in_range = value;

View file

@ -73,13 +73,22 @@ class OutputsWidget: public Widget
void twoColumns()
{
uint8_t endColumn = drawChannels(zone.x, zone.y, zone.w / 2, zone.h, persistentData->options[0].unsignedValue, persistentData->options[1].boolValue, persistentData->options[2].unsignedValue);
drawChannels(zone.x + zone.w / 2 + 2, zone.y, zone.w / 2, zone.h, endColumn + 1, persistentData->options[1].boolValue, persistentData->options[2].unsignedValue);
uint8_t endColumn = drawChannels(zone.x, zone.y, zone.w / 2, zone.h,
persistentData->options[0].value.unsignedValue,
persistentData->options[1].value.boolValue,
persistentData->options[2].value.unsignedValue);
drawChannels(zone.x + zone.w / 2 + 2, zone.y, zone.w / 2, zone.h, endColumn + 1,
persistentData->options[1].value.boolValue,
persistentData->options[2].value.unsignedValue);
}
void oneColumn()
{
drawChannels(zone.x, zone.y, zone.w, zone.h, persistentData->options[0].unsignedValue, persistentData->options[1].boolValue, persistentData->options[2].unsignedValue);
drawChannels(zone.x, zone.y, zone.w, zone.h,
persistentData->options[0].value.unsignedValue,
persistentData->options[1].value.boolValue,
persistentData->options[2].value.unsignedValue);
}
static const ZoneOption options[];

View file

@ -45,12 +45,18 @@ const ZoneOption TextWidget::options[] = {
void TextWidget::refresh()
{
lcdSetColor(persistentData->options[1].unsignedValue);
LcdFlags fontsize = FONTSIZE(persistentData->options[2].unsignedValue << 8);
if(persistentData->options[3].boolValue) {
lcdDrawSizedText(zone.x+1, zone.y+1, persistentData->options[0].stringValue, sizeof(persistentData->options[0].stringValue), ZCHAR|fontsize|BLACK);
lcdSetColor(persistentData->options[1].value.unsignedValue);
LcdFlags fontsize = FONTSIZE(persistentData->options[2].value.unsignedValue << 8);
if(persistentData->options[3].value.boolValue) {
lcdDrawSizedText(zone.x+1, zone.y+1,
persistentData->options[0].value.stringValue,
sizeof(persistentData->options[0].value.stringValue),
ZCHAR|fontsize|BLACK);
}
lcdDrawSizedText(zone.x, zone.y, persistentData->options[0].stringValue, sizeof(persistentData->options[0].stringValue), ZCHAR|fontsize|CUSTOM_COLOR);
lcdDrawSizedText(zone.x, zone.y,
persistentData->options[0].value.stringValue,
sizeof(persistentData->options[0].value.stringValue),
ZCHAR|fontsize|CUSTOM_COLOR);
}
BaseWidgetFactory<TextWidget> textWidget("Text", TextWidget::options);

View file

@ -40,7 +40,7 @@ const ZoneOption TimerWidget::options[] = {
void TimerWidget::refresh()
{
uint32_t index = persistentData->options[0].unsignedValue;
uint32_t index = persistentData->options[0].value.unsignedValue;
TimerData & timerData = g_model.timers[index];
TimerState & timerState = timersStates[index];

View file

@ -44,8 +44,8 @@ void ValueWidget::refresh()
{
const int NUMBERS_PADDING = 4;
mixsrc_t field = persistentData->options[0].unsignedValue;
lcdSetColor(persistentData->options[1].unsignedValue);
mixsrc_t field = persistentData->options[0].value.unsignedValue;
lcdSetColor(persistentData->options[1].value.unsignedValue);
int x = zone.x;
int y = zone.y;
@ -112,7 +112,7 @@ void ValueWidget::refresh()
}
}
if(persistentData->options[2].boolValue) {
if(persistentData->options[2].value.boolValue) {
drawSource(xLabel + 1, yLabel + 1, field, attrLabel|BLACK);
drawSourceValue(xValue + 1, yValue + 1, field, attrValue|BLACK);
}

View file

@ -60,7 +60,7 @@ class WidgetsContainer: public WidgetsContainerInterface
struct PersistentData {
ZonePersistentData zones[N];
ZoneOptionValue options[O];
ZoneOptionValueTyped options[O];
};
public:
@ -120,7 +120,7 @@ class WidgetsContainer: public WidgetsContainerInterface
inline ZoneOptionValue * getOptionValue(unsigned int index) const
{
return &persistentData->options[index];
return &persistentData->options[index].value;
}
virtual unsigned int getZonesCount() const = 0;

View file

@ -3,19 +3,20 @@
#define _ZONE_H_
#include <inttypes.h>
#include "storage/yaml/yaml_defs.h"
#define LEN_ZONE_OPTION_STRING 8
#if defined(_MSC_VER)
#define OPTION_VALUE_UNSIGNED(x) uint32_t(x)
#define OPTION_VALUE_SIGNED(x) uint32_t(x)
#define OPTION_VALUE_BOOL(x) bool(x)
#define OPTION_VALUE_STRING(...) *(ZoneOptionValue *)(const char *) #__VA_ARGS__
#define OPTION_VALUE_UNSIGNED(x) { uint32_t(x) }
#define OPTION_VALUE_SIGNED(x) { uint32_t(x) }
#define OPTION_VALUE_BOOL(x) { bool(x) }
#define OPTION_VALUE_STRING(...) { *(ZoneOptionValue *)(const char *) #__VA_ARGS__ }
#else
#define OPTION_VALUE_UNSIGNED(x) { .unsignedValue = (x) }
#define OPTION_VALUE_SIGNED(x) { .signedValue = (x) }
#define OPTION_VALUE_BOOL(x) { .boolValue = (x) }
#define OPTION_VALUE_STRING(...) { .stringValue = {__VA_ARGS__} }
#define OPTION_VALUE_STRING(...) { .stringValue = { __VA_ARGS__ } }
#endif
struct Zone
@ -31,6 +32,13 @@ union ZoneOptionValue
char stringValue[LEN_ZONE_OPTION_STRING];
};
enum ZoneOptionValueEnum {
ZOV_Unsigned=0,
ZOV_Signed,
ZOV_Bool,
ZOV_String
};
struct ZoneOption
{
enum Type {
@ -52,4 +60,34 @@ struct ZoneOption
ZoneOptionValue max;
};
struct ZoneOptionValueTyped
{
ZoneOptionValueEnum type;
ZoneOptionValue value FUNC(select_zov);
};
inline ZoneOptionValueEnum zoneValueEnumFromType(ZoneOption::Type type)
{
switch(type) {
case ZoneOption::File:
case ZoneOption::String:
return ZOV_String;
case ZoneOption::Integer:
return ZOV_Signed;
case ZoneOption::Bool:
return ZOV_Bool;
case ZoneOption::Color:
case ZoneOption::Timer:
case ZoneOption::Switch:
case ZoneOption::Source:
case ZoneOption::TextSize:
default:
return ZOV_Unsigned;
}
}
#endif

View file

@ -319,7 +319,7 @@ class LuaWidgetFactory: public WidgetFactory
lua_newtable(lsWidgets);
int i = 0;
for (const ZoneOption * option = options; option->name; option++, i++) {
l_pushtableint(option->name, persistentData->options[i].signedValue);
l_pushtableint(option->name, persistentData->options[i].value.signedValue);
}
if (lua_pcall(lsWidgets, 2, 1, 0) != 0) {
@ -349,7 +349,7 @@ void LuaWidget::update()
lua_newtable(lsWidgets);
int i = 0;
for (const ZoneOption * option = getOptions(); option->name; option++, i++) {
l_pushtableint(option->name, persistentData->options[i].signedValue);
l_pushtableint(option->name, persistentData->options[i].value.signedValue);
}
if (lua_pcall(lsWidgets, 2, 0, 0) != 0) {

View file

@ -1952,6 +1952,18 @@ void opentxInit()
// TODO topbar removed from new UI for now
// topbar = new Topbar(&g_model.topbarData);
// #if __clang__
// // clang does not like this at all, turn into a warning so that -Werror does not stop here
// // taking address of packed member 'topbarData' of class or structure 'ModelData' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member]
// #pragma clang diagnostic push
// #pragma clang diagnostic warning "-Waddress-of-packed-member"
// #endif
// topbar = new Topbar((Topbar::PersistentData*)(((uint8_t*)&g_model) + offsetof(ModelData,topbarData)));
// #if __clang__
// // Restore warnings
// #pragma clang diagnostic pop
// #endif
// lua widget state must also be prepared before the call to storageReadAll()
LUA_INIT_THEMES_AND_WIDGETS();
}

View file

@ -55,6 +55,10 @@
#if defined(COLORLCD)
const char RADIO_MODELSLIST_PATH[] = RADIO_PATH "/models.txt";
const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
#if defined(SDCARD_YAML)
const char RADIO_MODELSLIST_YAML_PATH[] = RADIO_PATH "/models.yml";
const char RADIO_SETTINGS_YAML_PATH[] = RADIO_PATH "/radio.yml";
#endif
#define SPLASH_FILE "splash.png"
#endif
@ -72,6 +76,9 @@ const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
#define SPORT_FIRMWARE_EXT ".frk"
#define FRSKY_FIRMWARE_EXT ".frsk"
#define MULTI_FIRMWARE_EXT ".bin"
#define YAML_EXT ".yml"
#define LEN_FILE_EXTENSION_MAX 5 // longest used, including the dot, excluding null term.
#if defined(COLORLCD)
#define BITMAPS_EXT BMP_EXT JPG_EXT PNG_EXT

View file

@ -355,7 +355,7 @@ void OpenTxSim::updateKeysAndSwitches(bool start)
// gruvin: Can't use Function keys on the Mac -- too many other app conflicts.
// The ordering of these keys, Q/W,E/R,T/Y,U/I matches the on screen
// order of trim sliders
static FXuint trimKeys[] = { KEY_E, KEY_R, KEY_U, KEY_I, KEY_R, KEY_E, KEY_Y, KEY_T, KEY_Q, KEY_W };
static FXuint trimKeys[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0 };
#else
static FXuint trimKeys[] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12 };
#endif
@ -432,11 +432,11 @@ long OpenTxSim::onTimeout(FXObject*, FXSelector, void*)
#if defined(ROTARY_ENCODER_NAVIGATION)
static bool rotencAction = false;
if (getApp()->getKeyState(KEY_X)) {
if (getApp()->getKeyState(KEY_X) || getApp()->getKeyState(KEY_plus)) {
if (!rotencAction) ROTARY_ENCODER_NAVIGATION_VALUE += ROTARY_ENCODER_GRANULARITY;
rotencAction = true;
}
else if (getApp()->getKeyState(KEY_W)) {
else if (getApp()->getKeyState(KEY_W) || getApp()->getKeyState(KEY_minus)) {
if (!rotencAction) ROTARY_ENCODER_NAVIGATION_VALUE -= ROTARY_ENCODER_GRANULARITY;
rotencAction = true;
}

View file

@ -316,6 +316,7 @@ void convertModelData_218_to_219(ModelData &model)
#endif
#if defined(PCBHORUS)
#if defined(FIXME) //TODO
memcpy(newModel.screenData, oldModel.screenData,
sizeof(newModel.screenData) +
sizeof(newModel.topbarData));
@ -342,7 +343,7 @@ void convertModelData_218_to_219(ModelData &model)
ZoneOptionValue & option = zoneData->widgetData.options[0];
option.unsignedValue = convertSource_218_to_219(option.unsignedValue);
}
#endif
#else
newModel.screensType = oldModel.frsky.screensType;
memmove(&newModel.screens, &oldModel.frsky.screens, sizeof(newModel.screens));

View file

@ -611,7 +611,8 @@ PACK(struct RadioData_v218 {
static inline void check_struct_218()
{
#if defined(PCBHORUS)
CHKSIZE(ModelData_v218, 9380);
// FIXME !!!
CHKSIZE(ModelData_v218, 10664);
#elif defined(PCBX9E)
CHKSIZE(ModelData_v218, 6520);
#elif defined(PCBX9D)

View file

@ -18,6 +18,9 @@
* GNU General Public License for more details.
*/
#ifndef _EEPROM_COMMON_H_
#define _EEPROM_COMMON_H_
#define EEPROM_MIN_MODEL_SIZE 256
uint16_t eeLoadModelData(uint8_t id);
@ -36,3 +39,10 @@ void storageClearRadioSettings();
bool storageReadRadioSettings(bool allowFixes = true);
void storageReadCurrentModel();
#if defined(EEPROM_RLC)
#include "eeprom_rlc.h"
#else
#include "eeprom_raw.h"
#endif
#endif

View file

@ -0,0 +1,79 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
//#include "eeprom_common.h"
void eepromCheck()
{
}
void storageFormat()
{
}
bool eepromOpen()
{
return true;
}
uint16_t eeLoadModelData(uint8_t index)
{
modelDefault(index);
return sizeof(g_model);
}
bool eeLoadGeneral()
{
generalDefault();
return true;
}
void eeLoadModelName(uint8_t id, char *name)
{
memclear(name, sizeof(g_model.header.name));
}
bool eeModelExists(uint8_t id)
{
return true;
}
void storageCheck(bool immediately)
{
}
void eeLoadModelHeader(uint8_t id, ModelHeader * header)
{
memclear(header, sizeof(ModelHeader));
}
bool eeCopyModel(uint8_t dst, uint8_t src)
{
return true;
}
void eeSwapModels(uint8_t id1, uint8_t id2)
{
}
void eeDeleteModel(uint8_t idx)
{
}

View file

@ -21,6 +21,11 @@
#include "modelslist.h"
using std::list;
#if defined(SDCARD_YAML)
#include "yaml/yaml_parser.h"
#include "yaml/yaml_modelslist.h"
#endif
ModelsList modelslist;
ModelCell::ModelCell(const char * name):
@ -29,6 +34,16 @@ ModelCell::ModelCell(const char * name):
strncpy(modelFilename, name, sizeof(modelFilename));
}
ModelCell::ModelCell(const char * name, uint8_t len)
: valid_rfData(false)
{
if (len > sizeof(modelFilename)-1)
len = sizeof(modelFilename)-1;
memcpy(modelFilename, name, len);
modelFilename[len] = '\0';
}
ModelCell::~ModelCell()
{
}
@ -45,15 +60,132 @@ void ModelCell::setModelName(char * name)
}
}
void ModelCell::setModelName(char* name, uint8_t len)
{
if (len > LEN_MODEL_NAME-1)
len = LEN_MODEL_NAME-1;
memcpy(modelName, name, len);
modelName[len] = '\0';
if (modelName[0] == 0) {
char * tmp;
strncpy(modelName, modelFilename, LEN_MODEL_NAME);
tmp = (char *) memchr(modelName, '.', LEN_MODEL_NAME);
if (tmp != NULL)
*tmp = 0;
}
//resetBuffer();
}
void ModelCell::setModelId(uint8_t moduleIdx, uint8_t id)
{
modelId[moduleIdx] = id;
}
// void ModelCell::resetBuffer()
// {
// if (buffer) {
// delete buffer;
// buffer = NULL;
// }
// }
// const BitmapBuffer * ModelCell::getBuffer()
// {
// if (!buffer) {
// loadBitmap();
// }
// return buffer;
// }
// void ModelCell::loadBitmap()
// {
// uint8_t version;
// PACK(struct {
// ModelHeader header;
// TimerData timers[MAX_TIMERS];
// }) partialmodel;
// const char * error = NULL;
// BitmapBuffer * tmp_buffer;
// if (strncmp(modelFilename, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME) == 0) {
// memcpy(&partialmodel.header, &g_model.header, sizeof(partialmodel));
// }
// else {
// #if !defined (SDCARD_YAML)
// error = readModel(modelFilename, (uint8_t *)&partialmodel.header, sizeof(partialmodel), &version);
// // LEN_BITMAP_NAME has now 4 bytes more
// if (version <= 218) {
// memmove(partialmodel.timers, &(partialmodel.header.bitmap[10]), sizeof(TimerData)*MAX_TIMERS);
// memclear(&(partialmodel.header.bitmap[10]), 4);
// }
// #else
// memset(&partialmodel.header,0,sizeof(partialmodel));
// #endif
// }
// if ((modelName[0] == 0) && ! error)
// setModelName(partialmodel.header.name); // resets buffer!!!
// tmp_buffer = new BitmapBuffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT);
// if (tmp_buffer == NULL) {
// return;
// }
// tmp_buffer->clear(TEXT_BGCOLOR);
// if (error) {
// tmp_buffer->drawText(5, 2, "(Invalid Model)", TEXT_COLOR);
// tmp_buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, TEXT_COLOR);
// }
// else {
// char timer[LEN_TIMER_STRING];
// tmp_buffer->drawSizedText(5, 2, modelName, /*LEN_MODEL_NAME*/strlen(modelName),
// SMLSIZE|TEXT_COLOR);
// getTimerString(timer, 0);
// for (uint8_t i = 0; i < MAX_TIMERS; i++) {
// if (partialmodel.timers[i].mode > 0 && partialmodel.timers[i].persistent) {
// getTimerString(timer, partialmodel.timers[i].value);
// break;
// }
// }
// tmp_buffer->drawText(101, 40, timer, TEXT_COLOR);
// for (int i=0; i<4; i++) {
// tmp_buffer->drawBitmapPattern(104+i*11, 25, LBM_SCORE0, TITLE_BGCOLOR);
// }
// GET_FILENAME(filename, BITMAPS_PATH, partialmodel.header.bitmap, "");
// const BitmapBuffer * bitmap = BitmapBuffer::load(filename);
// if (bitmap) {
// tmp_buffer->drawScaledBitmap(bitmap, 5, 24, 56, 32);
// delete bitmap;
// }
// else {
// tmp_buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, TEXT_COLOR);
// }
// }
// tmp_buffer->drawSolidHorizontalLine(5, 19, 143, LINE_COLOR);
// buffer = tmp_buffer;
// }
void ModelCell::save(FIL* file)
{
#if !defined(SDCARD_YAML)
f_puts(modelFilename, file);
f_putc('\n', file);
#else
f_puts(" - filename: ", file);
f_puts(modelFilename, file);
f_putc('\n', file);
f_puts(" name: ", file);
f_puts(modelName, file);
f_putc('\n', file);
#endif
}
void ModelCell::setRfData(ModelData* model)
@ -82,6 +214,7 @@ void ModelCell::setRfModuleData(uint8_t moduleIdx, ModuleData* modData)
bool ModelCell::fetchRfData()
{
#if !defined(SDCARD_YAML)
//TODO: use g_model in case fetching data for current model
//
char buf[256];
@ -127,6 +260,10 @@ bool ModelCell::fetchRfData()
error:
f_close(&file);
return false;
#else
return false;
#endif
}
ModelsCategory::ModelsCategory(const char * name)
@ -134,6 +271,15 @@ ModelsCategory::ModelsCategory(const char * name)
strncpy(this->name, name, sizeof(this->name));
}
ModelsCategory::ModelsCategory(const char * name, uint8_t len)
{
if (len > sizeof(this->name)-1)
len = sizeof(this->name)-1;
memcpy(this->name, name, len);
this->name[len] = '\0';
}
ModelsCategory::~ModelsCategory()
{
for (auto * model: *this) {
@ -143,6 +289,8 @@ ModelsCategory::~ModelsCategory()
ModelCell * ModelsCategory::addModel(const char * name)
{
if (!name) return NULL;
ModelCell * result = new ModelCell(name);
push_back(result);
return result;
@ -183,10 +331,16 @@ void ModelsCategory::moveModel(ModelCell * model, int8_t step)
void ModelsCategory::save(FIL * file)
{
#if !defined(SDCARD_YAML)
f_puts("[", file);
f_puts(name, file);
f_puts("]", file);
f_putc('\n', file);
#else
f_puts("- name: ", file);
f_puts(name, file);
f_putc('\n', file);
#endif
for (list<ModelCell *>::iterator it = begin(); it != end(); ++it) {
(*it)->save(file);
}
@ -228,8 +382,15 @@ bool ModelsList::load()
if (loaded)
return true;
#if !defined(SDCARD_YAML)
FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_OPEN_EXISTING | FA_READ);
#else
FRESULT result = f_open(&file, RADIO_MODELSLIST_YAML_PATH, FA_OPEN_EXISTING | FA_READ);
#endif
if (result == FR_OK) {
#if !defined(SDCARD_YAML)
// TXT reader
while (readNextLine(line, LEN_MODELS_IDX_LINE)) {
int len = strlen(line); // TODO could be returned by readNextLine
if (len > 2 && line[0] == '[' && line[len-1] == ']') {
@ -248,12 +409,32 @@ bool ModelsList::load()
currentCategory = category;
currentModel = model;
}
//parseModulesData(model, rf_data_str);
//TRACE("model=<%s>, valid_rfData=<%i>",model->modelFilename,model->valid_rfData);
model->fetchRfData();
modelsCount += 1;
}
}
#else
// YAML reader
TRACE("YAML modelslist reader");
YamlParser yp; //TODO: move to re-usable buffer
yp.init(get_modelslist_parser_calls(), get_modelslist_iter());
UINT bytes_read=0;
while (f_read(&file, line, sizeof(line), &bytes_read) == FR_OK) {
// reached EOF?
if (bytes_read == 0)
break;
if (yp.parse(line, bytes_read) != YamlParser::CONTINUE_PARSING)
break;
}
// debug output
//modelslist.dump();
#endif
f_close(&file);
}
@ -276,12 +457,18 @@ bool ModelsList::load()
void ModelsList::save()
{
#if !defined(SDCARD_YAML)
FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_CREATE_ALWAYS | FA_WRITE);
#else
FRESULT result = f_open(&file, RADIO_MODELSLIST_YAML_PATH, FA_CREATE_ALWAYS | FA_WRITE);
#endif
if (result != FR_OK) {
return;
}
for (list<ModelsCategory *>::iterator it = categories.begin(); it != categories.end(); ++it) {
for (list<ModelsCategory *>::iterator it = categories.begin();
it != categories.end(); ++it) {
(*it)->save(&file);
}
@ -317,11 +504,16 @@ bool ModelsList::readNextLine(char * line, int maxlen)
return false;
}
ModelsCategory * ModelsList::createCategory()
ModelsCategory * ModelsList::createCategory(bool save)
{
ModelsCategory * result = new ModelsCategory("Category");
return createCategory("Category", save);
}
ModelsCategory * ModelsList::createCategory(const char* name, bool save)
{
ModelsCategory * result = new ModelsCategory(name);
categories.push_back(result);
save();
if (save) this->save();
return result;
}

View file

@ -23,7 +23,11 @@
#include <stdint.h>
#include <list>
#include "sdcard.h"
#if !defined(SDCARD_YAML)
#include "sdcard_raw.h"
#endif
#define MODELCELL_WIDTH 172
#define MODELCELL_HEIGHT 59
@ -48,11 +52,13 @@ class ModelCell
SimpleModuleData moduleData[NUM_MODULES];
explicit ModelCell(const char * name);
explicit ModelCell(const char * name, uint8_t len);
~ModelCell();
void save(FIL* file);
void setModelName(char* name);
void setModelName(char* name, uint8_t len);
void setRfData(ModelData* model);
void setModelId(uint8_t moduleIdx, uint8_t id);
@ -69,11 +75,13 @@ public:
char name[LEN_MODEL_FILENAME+1];
explicit ModelsCategory(const char * name);
explicit ModelsCategory(const char * name, uint8_t len);
~ModelsCategory();
ModelCell * addModel(const char * name);
void removeModel(ModelCell * model);
void moveModel(ModelCell * model, int8_t step);
void save(FIL * file);
};
@ -101,6 +109,11 @@ public:
return categories;
}
std::list<ModelsCategory *>& getCategories()
{
return categories;
}
void setCurrentCategorie(ModelsCategory * cat);
ModelsCategory * getCurrentCategory() const
@ -115,6 +128,10 @@ public:
return currentModel;
}
void incModelsCount() {
modelsCount++;
}
unsigned int getModelsCount() const
{
return modelsCount;
@ -122,7 +139,8 @@ public:
bool readNextLine(char * line, int maxlen);
ModelsCategory * createCategory();
ModelsCategory * createCategory(bool save=true);
ModelsCategory * createCategory(const char * name, bool save=true);
void removeCategory(ModelsCategory * category);
ModelCell * addModel(ModelsCategory * category, const char * name);

View file

@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "rambackup.h"
namespace Backup {
#define BACKUP

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _RAMBACKUP_H_
#define _RAMBACKUP_H_
#include "rlc.h"
PACK(struct RamBackup {
uint16_t size;
uint8_t data[4094];
});
extern RamBackup * ramBackup;
void rambackupWrite();
bool rambackupRestore();
#endif

View file

@ -22,6 +22,8 @@
#include <assert.h>
#include "debug.h"
#include "rlc.h"
#define CHECK_DST_SIZE() \
if (cur-dst >= (int)dstsize) { \
TRACE("RLC encoding size too big"); \

27
radio/src/storage/rlc.h Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _RLC_H_
#define _RLC_H_
unsigned int compress(uint8_t * dst, unsigned int dstsize, const uint8_t * src, unsigned int len);
unsigned int uncompress(uint8_t * dst, unsigned int dstsize, const uint8_t * src, unsigned int len);
#endif

View file

@ -0,0 +1,161 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "storage.h"
#include "sdcard_common.h"
#include "modelslist.h"
#include "conversions/conversions.h"
// defined either in sdcard_raw.cpp or sdcard_yaml.cpp
void storageCreateModelsList();
void getModelPath(char * path, const char * filename)
{
strcpy(path, STR_MODELS_PATH);
path[sizeof(MODELS_PATH)-1] = '/';
strcpy(&path[sizeof(MODELS_PATH)], filename);
}
void storageEraseAll(bool warn)
{
TRACE("storageEraseAll");
#if defined(LIBOPENUI)
// the theme has not been loaded before
static_cast<ThemeBase*>(theme)->load();
#endif
generalDefault();
modelDefault(1);
if (warn) {
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
}
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
storageFormat();
storageDirty(EE_GENERAL|EE_MODEL);
storageCheck(true);
}
void storageFormat()
{
sdCheckAndCreateDirectory(RADIO_PATH);
sdCheckAndCreateDirectory(MODELS_PATH);
storageCreateModelsList();
}
void storageCheck(bool immediately)
{
if (storageDirtyMsk & EE_GENERAL) {
TRACE("eeprom write general");
storageDirtyMsk -= EE_GENERAL;
const char * error = writeGeneralSettings();
if (error) {
TRACE("writeGeneralSettings error=%s", error);
}
}
if (storageDirtyMsk & EE_MODEL) {
TRACE("eeprom write model");
storageDirtyMsk -= EE_MODEL;
const char * error = writeModel();
if (error) {
TRACE("writeModel error=%s", error);
}
}
}
const char * createModel()
{
preModelLoad();
char filename[LEN_MODEL_FILENAME+1];
memset(filename, 0, sizeof(filename));
strcpy(filename, MODEL_FILENAME_PATTERN);
int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH);
if (index > 0) {
modelDefault(index);
memcpy(g_eeGeneral.currModelFilename, filename, sizeof(g_eeGeneral.currModelFilename));
storageDirty(EE_GENERAL);
storageDirty(EE_MODEL);
storageCheck(true);
}
postModelLoad(false);
return g_eeGeneral.currModelFilename;
}
const char * loadModel(const char * filename, bool alarms)
{
uint8_t version;
preModelLoad();
const char * error = readModel(filename, (uint8_t *)&g_model, sizeof(g_model), &version);
if (error) {
TRACE("loadModel error=%s", error);
}
if (error) {
modelDefault(0) ;
storageCheck(true);
alarms = false;
}
else if (version < EEPROM_VER) {
convertModelData(version);
}
postModelLoad(alarms);
return error;
}
void storageReadAll()
{
TRACE("storageReadAll");
if (loadRadioSettings() != nullptr) {
storageEraseAll(true);
}
for (uint8_t i = 0; languagePacks[i] != nullptr; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
if (loadModel(g_eeGeneral.currModelFilename, false) != nullptr) {
sdCheckAndCreateDirectory(MODELS_PATH);
createModel();
}
// Wipe models list in case
// it's being reloaded after USB connection
modelslist.clear();
// and reload the list
modelslist.load();
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SDCARD_COMMON_H_
#define _SDCARD_COMMON_H_
#include "ff.h"
#define DEFAULT_CATEGORY "Models"
#if defined(SDCARD_RAW)
#define DEFAULT_MODEL_FILENAME "model1.bin"
#define MODEL_FILENAME_PATTERN "model.bin"
#elif defined(SDCARD_YAML)
#define DEFAULT_MODEL_FILENAME "model1.yml"
#define MODEL_FILENAME_PATTERN "model.yml"
#endif
// opens radio.bin or model file
const char * openFile(const char * fullpath, FIL * file, uint16_t * size, uint8_t * version);
void getModelPath(char * path, const char * filename);
const char * readModel(const char * filename, uint8_t * buffer, uint32_t size, uint8_t * version);
const char * loadModel(const char * filename, bool alarms=true);
const char * createModel();
const char * writeModel();
const char * loadRadioSettings();
const char * writeGeneralSettings();
const char * loadRadioSettings(const char * path);
const char * loadRadioSettings();
#endif // _SDCARD_RAW_H_

View file

@ -22,13 +22,6 @@
#include "modelslist.h"
#include "conversions/conversions.h"
void getModelPath(char * path, const char * filename)
{
strcpy(path, STR_MODELS_PATH);
path[sizeof(MODELS_PATH)-1] = '/';
strcpy(&path[sizeof(MODELS_PATH)], filename);
}
const char * writeFile(const char * filename, const uint8_t * data, uint16_t size)
{
TRACE("writeFile(%s)", filename);
@ -91,6 +84,8 @@ const char * openFile(const char * fullpath, FIL * file, uint16_t * size, uint8_
return SDCARD_ERROR(result);
}
//TODO: move this code into some checkCompatibleFormat()
*version = (uint8_t)buf[4];
if (*(uint32_t*)&buf[0] != OTX_FOURCC || *version < FIRST_CONV_EEPROM_VER || *version > EEPROM_VER || buf[5] != 'M') {
f_close(file);
@ -131,32 +126,6 @@ const char * readModel(const char * filename, uint8_t * buffer, uint32_t size, u
return loadFile(path, buffer, size, version);
}
const char * loadModel(const char * filename, bool alarms)
{
uint8_t version;
preModelLoad();
const char * error = readModel(filename, (uint8_t *)&g_model, sizeof(g_model), &version);
if (error) {
TRACE("loadModel error=%s", error);
}
if (error) {
modelDefault(0) ;
storageCheck(true);
alarms = false;
}
#if defined(EEPROM_CONVERSIONS)
else if (version < EEPROM_VER) {
convertModelData(version);
}
#endif
postModelLoad(alarms);
return error;
}
const char * loadRadioSettings(const char * path)
{
@ -188,55 +157,6 @@ const char * writeGeneralSettings()
return writeFile(RADIO_SETTINGS_PATH, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
}
void storageCheck(bool immediately)
{
if (storageDirtyMsk & EE_GENERAL) {
TRACE("Storage write general");
storageDirtyMsk -= EE_GENERAL;
const char * error = writeGeneralSettings();
if (error) {
TRACE("writeGeneralSettings error=%s", error);
}
}
if (storageDirtyMsk & EE_MODEL) {
TRACE("Storage write current model");
storageDirtyMsk -= EE_MODEL;
const char * error = writeModel();
if (error) {
TRACE("writeModel error=%s", error);
}
}
}
void storageReadAll()
{
TRACE("storageReadAll");
if (loadRadioSettings() != nullptr) {
storageEraseAll(true);
}
for (uint8_t i = 0; languagePacks[i] != nullptr; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
if (loadModel(g_eeGeneral.currModelFilename, false) != nullptr) {
sdCheckAndCreateDirectory(MODELS_PATH);
createModel();
}
// Wipe models list in case
// it's being reloaded after USB connection
modelslist.clear();
// and reload the list
modelslist.load();
}
void storageCreateModelsList()
{
FIL file;
@ -247,54 +167,3 @@ void storageCreateModelsList()
f_close(&file);
}
}
void storageFormat()
{
sdCheckAndCreateDirectory(RADIO_PATH);
sdCheckAndCreateDirectory(MODELS_PATH);
storageCreateModelsList();
}
const char * createModel()
{
preModelLoad();
char filename[LEN_MODEL_FILENAME+1];
memset(filename, 0, sizeof(filename));
strcpy(filename, "model.bin");
unsigned int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH);
if (index > 0) {
modelDefault(index);
memcpy(g_eeGeneral.currModelFilename, filename, sizeof(g_eeGeneral.currModelFilename));
storageDirty(EE_GENERAL);
storageDirty(EE_MODEL);
storageCheck(true);
}
postModelLoad(false);
return g_eeGeneral.currModelFilename;
}
void storageEraseAll(bool warn)
{
TRACE("storageEraseAll");
#if defined(LIBOPENUI)
// the theme has not been loaded before
static_cast<ThemeBase*>(theme)->load();
#endif
generalDefault();
modelDefault(1);
if (warn) {
ALERT(STR_STORAGE_WARNING, STR_BAD_RADIO_DATA, AU_BAD_RADIODATA);
}
RAISE_ALERT(STR_STORAGE_WARNING, STR_STORAGE_FORMAT, NULL, AU_NONE);
storageFormat();
storageDirty(EE_GENERAL|EE_MODEL);
storageCheck(true);
}

View file

@ -1,48 +1,8 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SDCARD_RAW_H_
#define _SDCARD_RAW_H_
#include "ff.h"
#include "FatFs/ff.h"
#define DEFAULT_CATEGORY "Models"
#define DEFAULT_MODEL_FILENAME "model1.bin"
const char * openFile(const char * fullpath, FIL* file, uint16_t* size);
// opens radio.bin or model file
const char * openFile(const char * fullpath, FIL * file, uint16_t * size, uint8_t * version);
void getModelPath(char * path, const char * filename);
const char * readModel(const char * filename, uint8_t * buffer, uint32_t size, uint8_t * version);
const char * loadModel(const char * filename, bool alarms=true);
const char * createModel();
const char * loadRadioSettings(const char * path);
const char * loadRadioSettings();
PACK(struct RamBackup {
uint16_t size;
uint8_t data[4094];
});
extern RamBackup * ramBackup;
#endif // _SDCARD_RAW_H_
#endif

View file

@ -0,0 +1,194 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "storage.h"
#include "sdcard_common.h"
#include "modelslist.h"
#include "yaml/yaml_tree_walker.h"
#include "yaml/yaml_parser.h"
#include "yaml/yaml_datastructs.h"
const char * readYamlFile(const char* fullpath, const YamlParserCalls* calls, void* parser_ctx)
{
FIL file;
UINT bytes_read;
FRESULT result = f_open(&file, fullpath, FA_OPEN_EXISTING | FA_READ);
if (result != FR_OK) {
return SDCARD_ERROR(result);
}
YamlParser yp; //TODO: move to re-usable buffer
yp.init(calls, parser_ctx);
char buffer[32];
while (f_read(&file, buffer, sizeof(buffer), &bytes_read) == FR_OK) {
// reached EOF?
if (bytes_read == 0)
break;
if (yp.parse(buffer, bytes_read) != YamlParser::CONTINUE_PARSING)
break;
}
f_close(&file);
return NULL;
}
//
// Generic storage interface
//
void storageCreateModelsList()
{
modelslist.clear();
ModelsCategory* cat = modelslist.createCategory(DEFAULT_CATEGORY, false);
cat->addModel(DEFAULT_MODEL_FILENAME);
modelslist.save();
}
//
// SDCARD storage interface
//
const char * loadRadioSettings()
{
// YAML reader
TRACE("YAML radio settings reader");
YamlTreeWalker tree;
tree.reset(get_radiodata_nodes(), (uint8_t*)&g_eeGeneral);
return readYamlFile(RADIO_SETTINGS_YAML_PATH, YamlTreeWalker::get_parser_calls(), &tree);
}
struct yaml_writer_ctx {
FIL* file;
FRESULT result;
};
static bool yaml_writer(void* opaque, const char* str, size_t len)
{
UINT bytes_written;
yaml_writer_ctx* ctx = (yaml_writer_ctx*)opaque;
TRACE_NOCRLF("%.*s",len,str);
ctx->result = f_write(ctx->file, str, len, &bytes_written);
return (ctx->result == FR_OK) && (bytes_written == len);
}
const char * writeGeneralSettings()
{
// YAML reader
TRACE("YAML radio settings writer");
FIL file;
FRESULT result = f_open(&file, RADIO_SETTINGS_YAML_PATH, FA_CREATE_ALWAYS | FA_WRITE);
if (result != FR_OK) {
return SDCARD_ERROR(result);
}
YamlTreeWalker tree;
tree.reset(get_radiodata_nodes(), (uint8_t*)&g_eeGeneral);
yaml_writer_ctx ctx;
ctx.file = &file;
ctx.result = FR_OK;
if (!tree.generate(yaml_writer, &ctx)) {
if (ctx.result != FR_OK) {
f_close(&file);
return SDCARD_ERROR(ctx.result);
}
}
f_close(&file);
return NULL;
}
const char * readModel(const char * filename, uint8_t * buffer, uint32_t size, uint8_t * version)
{
// YAML reader
TRACE("YAML model reader");
char path[256];
getModelPath(path, filename);
YamlTreeWalker tree;
tree.reset(get_modeldata_nodes(), buffer);
// wipe memory before reading YAML
memset(buffer,0,size);
//#if defined(FLIGHT_MODES) && defined(GVARS)
// reset GVars to default values
// Note: taken from opentx.cpp::modelDefault()
//TODO: new func in gvars
for (int p=1; p<MAX_FLIGHT_MODES; p++) {
for (int i=0; i<MAX_GVARS; i++) {
g_model.flightModeData[p].gvars[i] = GVAR_MAX+1;
}
}
//#endif
return readYamlFile(path, YamlTreeWalker::get_parser_calls(), &tree);
}
const char * writeModel()
{
// YAML reader
TRACE("YAML model writer");
char path[256];
getModelPath(path, g_eeGeneral.currModelFilename);
FIL file;
FRESULT result = f_open(&file, path, FA_CREATE_ALWAYS | FA_WRITE);
if (result != FR_OK) {
return SDCARD_ERROR(result);
}
YamlTreeWalker tree;
tree.reset(get_modeldata_nodes(), (uint8_t*)&g_model);
yaml_writer_ctx ctx;
ctx.file = &file;
ctx.result = FR_OK;
if (!tree.generate(yaml_writer, &ctx)) {
if (ctx.result != FR_OK) {
f_close(&file);
return SDCARD_ERROR(ctx.result);
}
}
f_close(&file);
return NULL;
}

View file

@ -43,32 +43,34 @@ extern tmr10ms_t rambackupDirtyTime10ms;
#define TIME_TO_RAMBACKUP() (rambackupDirtyMsk && (tmr10ms_t)(get_tmr10ms() - rambackupDirtyTime10ms) >= (tmr10ms_t)100)
#endif
//
// Generic storage interface
//
void storageEraseAll(bool warn);
void storageFormat();
void storageReadAll();
void storageDirty(uint8_t msk);
void storageCheck(bool immediately);
//
// Generic storage functions (implemented in storage_common.cpp)
//
void storageDirty(uint8_t msk);
void storageFlushCurrentModel();
void postRadioSettingsLoad();
void preModelLoad();
void postModelLoad(bool alarms);
void checkExternalAntenna();
#if defined(EEPROM_RLC)
#if defined(EEPROM)
#include "eeprom_common.h"
#include "eeprom_rlc.h"
#elif defined(EEPROM)
#include "eeprom_common.h"
#include "eeprom_raw.h"
#elif defined(SDCARD)
#include "sdcard_raw.h"
#endif
#if defined(SDCARD_RAW) || defined(SDCARD_YAML)
#include "sdcard_common.h"
#endif
#if defined(RAMBACKUP)
void rambackupWrite();
bool rambackupRestore();
unsigned int compress(uint8_t * dst, unsigned int dstsize, const uint8_t * src, unsigned int len);
unsigned int uncompress(uint8_t * dst, unsigned int dstsize, const uint8_t * src, unsigned int len);
#include "rambackup.h"
#endif
#endif // _STORAGE_H_

View file

@ -0,0 +1,46 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(SRC ${SRC} storage/yaml/yaml_tree_walker.cpp
storage/yaml/yaml_parser.cpp
storage/yaml/yaml_bits.cpp
storage/yaml/yaml_modelslist.cpp
storage/yaml/yaml_datastructs.cpp)
if(PCB STREQUAL X12S)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_x12s.cpp)
elseif(PCB STREQUAL X10)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_x10.cpp)
else()
message(FATAL_ERROR "PCB '${PCB}' is not supported by YAML storage")
endif()
set(YAML_GEN ${RADIO_DIRECTORY}/util/generate_yaml.py)
set(YAML_GEN_TEMPLATE ${RADIO_DIRECTORY}/util/yaml_parser.tmpl)
SET(YAML_NODES "\"RadioData,ModelData\"")
set(YAML_GEN_ARGS myeeprom.h ${YAML_GEN_TEMPLATE} ${YAML_NODES} -DYAML_GENERATOR)
get_property(flags DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
foreach(flag ${flags})
#message(STATUS "dir='${dir}'")
set(YAML_GEN_ARGS ${YAML_GEN_ARGS} -D${flag})
endforeach()
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
#message(STATUS "dir='${dir}'")
set(YAML_GEN_ARGS ${YAML_GEN_ARGS} -I${dir})
endforeach()
set(YAML_GEN_ARGS ${YAML_GEN_ARGS} -DRTOS_COOS -Wno-inconsistent-missing-override)
#message(STATUS "YAML_GEN_ARGS=${YAML_GEN_ARGS}")
add_custom_target(yaml_data
WORKING_DIRECTORY ${RADIO_DIRECTORY}/src
COMMAND ${PYTHON_EXECUTABLE} ${YAML_GEN} ${YAML_GEN_ARGS} > ${YAML_GEN_OUTPUT}
DEPENDS ${RADIO_DIRECTORY}/src/datastructs.h
${RADIO_DIRECTORY}/src/dataconstants.h
${RADIO_DIRECTORY}/src/myeeprom.h
${RADIO_DIRECTORY}/util/generate_yaml.py
)

View file

@ -0,0 +1,137 @@
#include <stdio.h>
#include "yaml_bits.h"
#include "yaml_parser.h"
#define MASK_LOWER(bits) ((1 << (bits)) - 1)
#define MASK_UPPER(bits) (0xFF << bits)
void yaml_put_bits(uint8_t* dst, uint32_t i, uint32_t bit_ofs, uint32_t bits)
{
i &= ((1UL << bits) - 1);
if (bit_ofs) {
*dst &= MASK_LOWER(bit_ofs);
*(dst++) |= (i << bit_ofs) & 0xFF;
if (bits <= 8 - bit_ofs)
return;
bits -= 8 - bit_ofs;
i = i >> (8 - bit_ofs);
}
while(bits >= 8) {
*(dst++) = i & 0xFF;
bits -= 8;
i = i >> 8;
}
if (bits) {
uint8_t mask = MASK_UPPER(bits);
*dst &= mask;
*dst |= i & ~mask;
}
}
uint32_t yaml_get_bits(uint8_t* src, uint32_t bit_ofs, uint32_t bits)
{
uint32_t i = 0;
uint32_t bit_shift = 0;
if (bit_ofs) {
i = (*(src++) & MASK_UPPER(bit_ofs)) >> bit_ofs;
if (bits <= 8 - bit_ofs) {
i &= MASK_LOWER(bits);
return i;
}
bit_shift = 8 - bit_ofs;
bits -= bit_shift;
}
while(bits >= 8) {
i |= (uint32_t)*(src++) << bit_shift;
bits -= 8;
bit_shift += 8;
}
if (bits) {
i |= ((uint32_t)*src & MASK_LOWER(bits)) << bit_shift;
}
return i;
}
bool yaml_is_zero(uint8_t* data, uint32_t bitoffs, uint32_t bits)
{
return !yaml_get_bits(data + (bitoffs>>3UL), bitoffs & 0x7, bits);
}
int32_t yaml_str2int(const char* val, uint8_t val_len)
{
bool neg = false;
int i_val = 0;
for(uint8_t i=0; i < val_len; i++) {
if (val[i] == '-')
neg = true;
else if (val[i] >= '0' && val[i] <= '9') {
i_val = i_val * 10 + (val[i] - '0');
}
}
return neg ? -i_val : i_val;
}
uint32_t yaml_str2uint(const char* val, uint8_t val_len)
{
uint32_t i_val = 0;
for(uint8_t i=0; i < val_len; i++) {
if (val[i] >= '0' && val[i] <= '9') {
i_val = i_val * 10 + (val[i] - '0');
}
}
return i_val;
}
static char int2str_buffer[MAX_STR] = {0};
static const char _int2str_lookup[] = { '0', '1', '2', '3', '4', '5', '6' , '7', '8', '9' };
char* yaml_unsigned2str(uint32_t i)
{
char* c = &(int2str_buffer[MAX_STR-2]);
do {
*(c--) = _int2str_lookup[i % 10];
i = i / 10;
} while((c > int2str_buffer) && i);
return (c + 1);
}
char* yaml_signed2str(int32_t i)
{
if (i < 0) {
char* c = yaml_unsigned2str(-i);
*(--c) = '-';
return c;
}
return yaml_unsigned2str((uint32_t)i);
}
int32_t yaml_to_signed(uint32_t i, uint32_t bits)
{
if (i & (1 << (bits-1))) {
i |= 0xFFFFFFFF << bits;
}
return i;
}

View file

@ -0,0 +1,20 @@
#ifndef _yaml_bits_h_
#define _yaml_bits_h_
#include <stdint.h>
void yaml_put_bits(uint8_t* dst, uint32_t i, uint32_t bit_ofs, uint32_t bits);
uint32_t yaml_get_bits(uint8_t* src, uint32_t bit_ofs, uint32_t bits);
// assumes bits is a multiple of 8
bool yaml_is_zero(uint8_t* data, uint32_t bitoffs, uint32_t bits);
int32_t yaml_str2int(const char* val, uint8_t val_len);
uint32_t yaml_str2uint(const char* val, uint8_t val_len);
char* yaml_unsigned2str(uint32_t i);
char* yaml_signed2str(int32_t i);
int32_t yaml_to_signed(uint32_t i, uint32_t bits);
#endif

View file

@ -0,0 +1,13 @@
#include "opentx.h"
#include "yaml_node.h"
#include "yaml_datastructs_funcs.cpp"
#if defined(PCBX10)
#include "yaml_datastructs_x10.cpp"
#elif defined(PCBX12S)
#include "yaml_datastructs_x12s.cpp"
#else
#error "Board not supported by YAML storage"
#endif

View file

@ -0,0 +1,9 @@
#ifndef _YAML_DATASTRUCTS_H_
#define _YAML_DATASTRUCTS_H_
struct YamlNode;
const YamlNode* get_radiodata_nodes();
const YamlNode* get_modeldata_nodes();
#endif

View file

@ -0,0 +1,361 @@
#include "opentx.h"
#include "yaml_bits.h"
#include "yaml_tree_walker.h"
#define GVAR_SMALL 128
static uint32_t in_read_weight(const YamlNode* node, const char* val, uint8_t val_len)
{
if ((val_len == 4)
&& (val[0] == '-')
&& (val[1] == 'G')
&& (val[2] == 'V')
&& (val[3] >= '1')
&& (val[3] <= '9')) {
TRACE("%.*s -> %i\n", val_len, val, GVAR_SMALL - (val[3] - '0'));
return GVAR_SMALL - (val[3] - '0'); // -GVx => 128 - x
}
if ((val_len == 3)
&& (val[0] == 'G')
&& (val[1] == 'V')
&& (val[2] >= '1')
&& (val[2] <= '9')) {
TRACE("%.*s -> %i\n", val_len, val, -GVAR_SMALL + (val[2] - '1'));
return -GVAR_SMALL + (val[2] - '1'); // GVx => -128 + (x-1)
}
return (uint32_t)yaml_str2int(val, val_len);
}
static bool in_write_weight(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque)
{
int32_t sval = yaml_to_signed(val,node->size);
if (sval > GVAR_SMALL-11 && sval < GVAR_SMALL-1) {
char n = GVAR_SMALL - sval + '0';
return wf(opaque, "-GV", 3) && wf(opaque, &n, 1);
}
else if (sval < -GVAR_SMALL+11 && sval > -GVAR_SMALL+1) {
char n = val - GVAR_SMALL + '1';
return wf(opaque, "GV", 2) && wf(opaque, &n, 1);
}
char* s = yaml_signed2str(sval);
return wf(opaque, s, strlen(s));
}
extern const struct YamlIdStr enum_MixSources[];
static uint32_t r_mixSrcRaw(const YamlNode* node, const char* val, uint8_t val_len)
{
if (val_len > 0 && val[0] == 'I') {
return yaml_str2uint(val+1, val_len-1) + MIXSRC_FIRST_INPUT;
}
return yaml_parse_enum(enum_MixSources, val, val_len);
}
static bool w_mixSrcRaw(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque)
{
const char* str = nullptr;
if (val >= MIXSRC_FIRST_INPUT
&& val <= MIXSRC_LAST_INPUT) {
if (!wf(opaque, "I", 1))
return false;
str = yaml_unsigned2str(val - MIXSRC_FIRST_INPUT);
}
else {
str = yaml_output_enum(val, enum_MixSources);
}
if (str) {
return wf(opaque, str, strlen(str));
}
return true;
}
static uint32_t r_vbat_min(const YamlNode* node, const char* val, uint8_t val_len)
{
int32_t v = yaml_str2int(val, val_len);
return (uint32_t)(v - 90);
}
static bool w_vbat_min(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque)
{
char* s = yaml_signed2str(yaml_to_signed(val,node->size) + 90);
return wf(opaque, s, strlen(s));
}
static uint32_t r_vbat_max(const YamlNode* node, const char* val, uint8_t val_len)
{
int32_t v = yaml_str2int(val, val_len);
return (uint32_t)(v - 120);
}
static bool w_vbat_max(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque)
{
char* s = yaml_signed2str(yaml_to_signed(val,node->size) + 120);
return wf(opaque, s, strlen(s));
}
static uint8_t select_zov(uint8_t* data, uint32_t bitoffs)
{
data += bitoffs >> 3UL;
data -= sizeof(ZoneOptionValueEnum);
ZoneOptionValueEnum* p_zovt = (ZoneOptionValueEnum*)data;
return *p_zovt;
}
static uint8_t select_mod_type(uint8_t* data, uint32_t bitoffs)
{
data += bitoffs >> 3UL;
data -= offsetof(ModuleData, ppm);
switch(((ModuleData*)data)->type) {
case MODULE_TYPE_NONE:
case MODULE_TYPE_PPM:
case MODULE_TYPE_DSM2:
case MODULE_TYPE_CROSSFIRE:
return 1;
case MODULE_TYPE_MULTIMODULE:
return 2;
case MODULE_TYPE_XJT_PXX1:
case MODULE_TYPE_R9M_PXX1:
case MODULE_TYPE_R9M_LITE_PXX1:
case MODULE_TYPE_R9M_LITE_PRO_PXX1:
return 3;
case MODULE_TYPE_SBUS:
return 4;
case MODULE_TYPE_ISRM_PXX2:
case MODULE_TYPE_R9M_PXX2:
case MODULE_TYPE_R9M_LITE_PXX2:
case MODULE_TYPE_R9M_LITE_PRO_PXX2:
case MODULE_TYPE_XJT_LITE_PXX2:
return 5;
}
return 0;
}
static uint8_t select_custom_fn(uint8_t* data, uint32_t bitoffs)
{
// always use 'all'
return 1;
}
static uint8_t select_script_input(uint8_t* data, uint32_t bitoffs)
{
// always use 'value'
return 0;
}
static uint8_t select_id1(uint8_t* data, uint32_t bitoffs)
{
// always use 'id'
return 0;
}
static uint8_t select_id2(uint8_t* data, uint32_t bitoffs)
{
// always use 'instance'
return 0;
}
static uint8_t select_sensor_cfg(uint8_t* data, uint32_t bitoffs)
{
// always use 'param'
return 5;
}
static uint32_t sw_read(const char* val, uint8_t val_len)
{
return yaml_parse_enum(enum_MixSources, val, val_len) - MIXSRC_FIRST_SWITCH;
}
static bool sw_write(uint32_t idx, yaml_writer_func wf, void* opaque)
{
const char* str = yaml_output_enum(idx + MIXSRC_FIRST_SWITCH, enum_MixSources);
return wf(opaque, str, strlen(str));
}
static const struct YamlIdStr enum_SwitchConfig[] = {
{ SWITCH_NONE, "none" },
{ SWITCH_TOGGLE, "toggle" },
{ SWITCH_2POS, "2pos" },
{ SWITCH_3POS, "3pos" },
{ 0, NULL }
};
static const struct YamlNode struct_switchConfig[] = {
YAML_IDX_CUST( "sw", sw_read, sw_write ),
YAML_ENUM( "type", 2, enum_SwitchConfig),
YAML_END
};
static uint32_t pot_read(const char* val, uint8_t val_len)
{
return yaml_parse_enum(enum_MixSources, val, val_len) - MIXSRC_FIRST_POT;
}
static bool pot_write(uint32_t idx, yaml_writer_func wf, void* opaque)
{
const char* str = yaml_output_enum(idx + MIXSRC_FIRST_POT, enum_MixSources);
return wf(opaque, str, strlen(str));
}
static const struct YamlIdStr enum_PotConfig[] = {
{ POT_NONE, "none" },
{ POT_WITH_DETENT, "with_detent" },
{ POT_MULTIPOS_SWITCH, "multipos_switch" },
{ POT_WITHOUT_DETENT, "without_detent" },
{ 0, NULL }
};
static const struct YamlNode struct_potConfig[] = {
YAML_IDX_CUST( "pot", pot_read, pot_write ),
YAML_ENUM( "type", 2, enum_PotConfig),
YAML_END
};
static uint32_t slider_read(const char* val, uint8_t val_len)
{
return yaml_parse_enum(enum_MixSources, val, val_len) - MIXSRC_FIRST_SLIDER;
}
static bool slider_write(uint32_t idx, yaml_writer_func wf, void* opaque)
{
const char* str = yaml_output_enum(idx + MIXSRC_FIRST_SLIDER, enum_MixSources);
return wf(opaque, str, strlen(str));
}
static const struct YamlIdStr enum_SliderConfig[] = {
{ SLIDER_NONE, "none" },
{ SLIDER_WITH_DETENT, "with_detent" },
{ 0, NULL }
};
static const struct YamlNode struct_sliderConfig[] = {
YAML_IDX_CUST( "sl", slider_read, slider_write ),
YAML_ENUM( "type", 1, enum_SliderConfig),
YAML_END
};
extern const struct YamlIdStr enum_SwitchSources[];
static uint32_t r_swtchSrc(const YamlNode* node, const char* val, uint8_t val_len)
{
int32_t ival=0;
bool neg = false;
if (val_len > 0 && val[0] == '!') {
neg = true;
val++;
val_len--;
}
if (val_len > 3
&& val[0] == '6'
&& val[1] == 'P'
&& (val[2] >= '0' && val[2] <= '9')
&& (val[3] >= '0' && val[3] < (XPOTS_MULTIPOS_COUNT + '0'))) {
ival = (val[2] - '0') * XPOTS_MULTIPOS_COUNT + (val[3] - '0')
+ SWSRC_FIRST_MULTIPOS_SWITCH;
}
else if (val_len >= 2
&& val[0] == 'L'
&& (val[1] >= '0' && val[1] <= '9')) {
ival = SWSRC_FIRST_LOGICAL_SWITCH + yaml_str2int(val+1, val_len-1) - 1;
}
//TODO: Flight modes ('FM[0-9]')
//TODO: Sensors ('Sensor[0-9]')
else {
ival = yaml_parse_enum(enum_SwitchSources, val, val_len);
}
return neg ? -ival : ival;
}
static bool w_swtchSrc(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque)
{
int32_t sval = yaml_to_signed(val, node->size);
if (sval < 0) {
wf(opaque, "!", 1);
sval = abs(sval);
}
const char* str = NULL;
if (sval >= SWSRC_FIRST_MULTIPOS_SWITCH
&& sval <= SWSRC_LAST_MULTIPOS_SWITCH) {
wf(opaque, "6P", 2);
// pot #: start with 6P1
sval -= SWSRC_FIRST_MULTIPOS_SWITCH;
str = yaml_unsigned2str(sval / XPOTS_MULTIPOS_COUNT);
wf(opaque,str, strlen(str));
// position
str = yaml_unsigned2str(sval % XPOTS_MULTIPOS_COUNT);
return wf(opaque,str, strlen(str));
}
else if (sval >= SWSRC_FIRST_LOGICAL_SWITCH
&& sval <= SWSRC_LAST_LOGICAL_SWITCH) {
wf(opaque, "L", 1);
str = yaml_unsigned2str(sval - SWSRC_FIRST_LOGICAL_SWITCH + 1);
return wf(opaque,str, strlen(str));
}
else if (sval >= SWSRC_FIRST_FLIGHT_MODE
&& sval <= SWSRC_LAST_FLIGHT_MODE) {
//TODO
return true;
}
else if (sval >= SWSRC_FIRST_SENSOR
&& sval <= SWSRC_LAST_SENSOR) {
//TODO
return true;
}
str = yaml_output_enum(sval, enum_SwitchSources);
return wf(opaque, str, strlen(str));
}
static bool cfn_is_active(uint8_t* data, uint32_t bitoffs)
{
data += bitoffs >> 3UL;
return ((CustomFunctionData*)data)->swtch;
}
static bool gvar_is_active(uint8_t* data, uint32_t bitoffs)
{
gvar_t* gvar = (gvar_t*)(data + (bitoffs>>3UL));
return *gvar != GVAR_MAX+1;
}
static bool fmd_is_active(uint8_t* data, uint32_t bitoffs)
{
uint32_t data_ofs = bitoffs >> 3UL;
if (data_ofs == offsetof(ModelData, flightModeData)) {
return !yaml_is_zero(data, bitoffs, sizeof(FlightModeData)*8);
}
bool is_active = !yaml_is_zero(data, bitoffs,
(sizeof(FlightModeData)
- sizeof(FlightModeData::gvars))*8);
FlightModeData* fmd = (FlightModeData*)(data + data_ofs);
for (uint8_t i=0; i<MAX_GVARS; i++) {
is_active |= fmd->gvars[i] != GVAR_MAX+1;
}
return is_active;
}

View file

@ -0,0 +1,770 @@
// generated by generate_yaml.py
//
// Enums first
//
const struct YamlIdStr enum_Functions[] = {
{ FUNC_OVERRIDE_CHANNEL, "OVERRIDE_CHANNEL" },
{ FUNC_TRAINER, "TRAINER" },
{ FUNC_INSTANT_TRIM, "INSTANT_TRIM" },
{ FUNC_RESET, "RESET" },
{ FUNC_SET_TIMER, "SET_TIMER" },
{ FUNC_ADJUST_GVAR, "ADJUST_GVAR" },
{ FUNC_VOLUME, "VOLUME" },
{ FUNC_SET_FAILSAFE, "SET_FAILSAFE" },
{ FUNC_RANGECHECK, "RANGECHECK" },
{ FUNC_BIND, "BIND" },
{ FUNC_FIRST_WITHOUT_ENABLE, "FIRST_WITHOUT_ENABLE" },
{ FUNC_PLAY_SOUND, "PLAY_SOUND" },
{ FUNC_PLAY_TRACK, "PLAY_TRACK" },
{ FUNC_PLAY_VALUE, "PLAY_VALUE" },
{ FUNC_RESERVE4, "RESERVE4" },
{ FUNC_PLAY_SCRIPT, "PLAY_SCRIPT" },
{ FUNC_RESERVE5, "RESERVE5" },
{ FUNC_BACKGND_MUSIC, "BACKGND_MUSIC" },
{ FUNC_BACKGND_MUSIC_PAUSE, "BACKGND_MUSIC_PAUSE" },
{ FUNC_VARIO, "VARIO" },
{ FUNC_HAPTIC, "HAPTIC" },
{ FUNC_LOGS, "LOGS" },
{ FUNC_BACKLIGHT, "BACKLIGHT" },
{ FUNC_SCREENSHOT, "SCREENSHOT" },
{ FUNC_MAX, "MAX" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
{ ZOV_Bool, "Bool" },
{ ZOV_String, "String" },
{ 0, NULL }
};
const struct YamlIdStr enum_MixSources[] = {
{ MIXSRC_NONE, "NONE" },
{ MIXSRC_Rud, "Rud" },
{ MIXSRC_Ele, "Ele" },
{ MIXSRC_Thr, "Thr" },
{ MIXSRC_Ail, "Ail" },
{ MIXSRC_S1, "S1" },
{ MIXSRC_6POS, "6POS" },
{ MIXSRC_S2, "S2" },
{ MIXSRC_EXT1, "EXT1" },
{ MIXSRC_EXT2, "EXT2" },
{ MIXSRC_LS, "LS" },
{ MIXSRC_RS, "RS" },
{ MIXSRC_MOUSE1, "MOUSE1" },
{ MIXSRC_MOUSE2, "MOUSE2" },
{ MIXSRC_MAX, "MAX" },
{ MIXSRC_CYC1, "CYC1" },
{ MIXSRC_CYC2, "CYC2" },
{ MIXSRC_CYC3, "CYC3" },
{ MIXSRC_TrimRud, "TrimRud" },
{ MIXSRC_TrimEle, "TrimEle" },
{ MIXSRC_TrimThr, "TrimThr" },
{ MIXSRC_TrimAil, "TrimAil" },
{ MIXSRC_TrimT5, "TrimT5" },
{ MIXSRC_TrimT6, "TrimT6" },
{ MIXSRC_SA, "SA" },
{ MIXSRC_SB, "SB" },
{ MIXSRC_SC, "SC" },
{ MIXSRC_SD, "SD" },
{ MIXSRC_SE, "SE" },
{ MIXSRC_SF, "SF" },
{ MIXSRC_SG, "SG" },
{ MIXSRC_SH, "SH" },
{ MIXSRC_SI, "SI" },
{ MIXSRC_SJ, "SJ" },
{ MIXSRC_SW1, "SW1" },
{ MIXSRC_CH1, "CH1" },
{ MIXSRC_CH2, "CH2" },
{ MIXSRC_CH3, "CH3" },
{ MIXSRC_CH4, "CH4" },
{ MIXSRC_CH5, "CH5" },
{ MIXSRC_CH6, "CH6" },
{ MIXSRC_CH7, "CH7" },
{ MIXSRC_CH8, "CH8" },
{ MIXSRC_CH9, "CH9" },
{ MIXSRC_CH10, "CH10" },
{ MIXSRC_CH11, "CH11" },
{ MIXSRC_CH12, "CH12" },
{ MIXSRC_CH13, "CH13" },
{ MIXSRC_CH14, "CH14" },
{ MIXSRC_CH15, "CH15" },
{ MIXSRC_CH16, "CH16" },
{ MIXSRC_GVAR1, "GVAR1" },
{ MIXSRC_TX_VOLTAGE, "TX_VOLTAGE" },
{ MIXSRC_TX_TIME, "TX_TIME" },
{ MIXSRC_TIMER1, "TIMER1" },
{ MIXSRC_TIMER2, "TIMER2" },
{ MIXSRC_TIMER3, "TIMER3" },
{ 0, NULL }
};
const struct YamlIdStr enum_LogicalSwitchesFunctions[] = {
{ LS_FUNC_NONE, "FUNC_NONE" },
{ LS_FUNC_VEQUAL, "FUNC_VEQUAL" },
{ LS_FUNC_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL" },
{ LS_FUNC_VPOS, "FUNC_VPOS" },
{ LS_FUNC_VNEG, "FUNC_VNEG" },
{ LS_FUNC_RANGE, "FUNC_RANGE" },
{ LS_FUNC_APOS, "FUNC_APOS" },
{ LS_FUNC_ANEG, "FUNC_ANEG" },
{ LS_FUNC_AND, "FUNC_AND" },
{ LS_FUNC_OR, "FUNC_OR" },
{ LS_FUNC_XOR, "FUNC_XOR" },
{ LS_FUNC_EDGE, "FUNC_EDGE" },
{ LS_FUNC_EQUAL, "FUNC_EQUAL" },
{ LS_FUNC_GREATER, "FUNC_GREATER" },
{ LS_FUNC_LESS, "FUNC_LESS" },
{ LS_FUNC_DIFFEGREATER, "FUNC_DIFFEGREATER" },
{ LS_FUNC_ADIFFEGREATER, "FUNC_ADIFFEGREATER" },
{ LS_FUNC_TIMER, "FUNC_TIMER" },
{ LS_FUNC_STICKY, "FUNC_STICKY" },
{ LS_FUNC_COUNT, "FUNC_COUNT" },
{ LS_FUNC_MAX, "FUNC_MAX" },
{ 0, NULL }
};
const struct YamlIdStr enum_SwitchSources[] = {
{ SWSRC_NONE, "NONE" },
{ SWSRC_SA0, "SA0" },
{ SWSRC_SA1, "SA1" },
{ SWSRC_SA2, "SA2" },
{ SWSRC_SB0, "SB0" },
{ SWSRC_SB1, "SB1" },
{ SWSRC_SB2, "SB2" },
{ SWSRC_SC0, "SC0" },
{ SWSRC_SC1, "SC1" },
{ SWSRC_SC2, "SC2" },
{ SWSRC_SD0, "SD0" },
{ SWSRC_SD1, "SD1" },
{ SWSRC_SD2, "SD2" },
{ SWSRC_SE0, "SE0" },
{ SWSRC_SE1, "SE1" },
{ SWSRC_SE2, "SE2" },
{ SWSRC_SF0, "SF0" },
{ SWSRC_SF1, "SF1" },
{ SWSRC_SF2, "SF2" },
{ SWSRC_SG0, "SG0" },
{ SWSRC_SG1, "SG1" },
{ SWSRC_SG2, "SG2" },
{ SWSRC_SH0, "SH0" },
{ SWSRC_SH1, "SH1" },
{ SWSRC_SH2, "SH2" },
{ SWSRC_SI0, "SI0" },
{ SWSRC_SI1, "SI1" },
{ SWSRC_SI2, "SI2" },
{ SWSRC_SJ0, "SJ0" },
{ SWSRC_SJ1, "SJ1" },
{ SWSRC_SJ2, "SJ2" },
{ SWSRC_TrimRudLeft, "TrimRudLeft" },
{ SWSRC_TrimRudRight, "TrimRudRight" },
{ SWSRC_TrimEleDown, "TrimEleDown" },
{ SWSRC_TrimEleUp, "TrimEleUp" },
{ SWSRC_TrimThrDown, "TrimThrDown" },
{ SWSRC_TrimThrUp, "TrimThrUp" },
{ SWSRC_TrimAilLeft, "TrimAilLeft" },
{ SWSRC_TrimAilRight, "TrimAilRight" },
{ SWSRC_TrimT5Down, "TrimT5Down" },
{ SWSRC_TrimT5Up, "TrimT5Up" },
{ SWSRC_TrimT6Down, "TrimT6Down" },
{ SWSRC_TrimT6Up, "TrimT6Up" },
{ SWSRC_SW1, "SW1" },
{ SWSRC_SW2, "SW2" },
{ SWSRC_ON, "ON" },
{ SWSRC_ONE, "ONE" },
{ SWSRC_TELEMETRY_STREAMING, "TELEMETRY_STREAMING" },
{ SWSRC_RADIO_ACTIVITY, "RADIO_ACTIVITY" },
{ SWSRC_OFF, "OFF" },
{ 0, NULL }
};
const struct YamlIdStr enum_ModuleType[] = {
{ MODULE_TYPE_NONE, "TYPE_NONE" },
{ MODULE_TYPE_PPM, "TYPE_PPM" },
{ MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" },
{ MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" },
{ MODULE_TYPE_DSM2, "TYPE_DSM2" },
{ MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" },
{ MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" },
{ MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" },
{ MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" },
{ MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" },
{ MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" },
{ MODULE_TYPE_R9M_LITE_PRO_PXX1, "TYPE_R9M_LITE_PRO_PXX1" },
{ MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" },
{ MODULE_TYPE_SBUS, "TYPE_SBUS" },
{ MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" },
{ MODULE_TYPE_FLYSKY, "TYPE_FLYSKY" },
{ MODULE_TYPE_COUNT, "TYPE_COUNT" },
{ MODULE_TYPE_MAX, "TYPE_MAX" },
{ 0, NULL }
};
//
// Structs last
//
static const struct YamlNode struct_CalibData[] = {
YAML_IDX,
YAML_SIGNED( "mid", 16 ),
YAML_SIGNED( "spanNeg", 16 ),
YAML_SIGNED( "spanPos", 16 ),
YAML_END
};
static const struct YamlNode struct_signed_16[] = {
YAML_IDX,
YAML_SIGNED( "val", 16 ),
YAML_END
};
static const struct YamlNode struct_TrainerMix[] = {
YAML_IDX,
YAML_UNSIGNED( "srcChn", 6 ),
YAML_UNSIGNED( "mode", 2 ),
YAML_SIGNED( "studWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_TrainerData[] = {
YAML_ARRAY("calib", 16, 4, struct_signed_16, NULL),
YAML_ARRAY("mix", 16, 4, struct_TrainerMix, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_1[] = {
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_anonymous_2[] = {
YAML_SIGNED( "val", 16 ),
YAML_UNSIGNED( "mode", 8 ),
YAML_UNSIGNED( "param", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_3[] = {
YAML_SIGNED( "val1", 32 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode union_anonymous_0_elmts[] = {
YAML_STRUCT("play", 48, struct_anonymous_1, NULL),
YAML_STRUCT("all", 48, struct_anonymous_2, NULL),
YAML_STRUCT("clear", 48, struct_anonymous_3, NULL),
YAML_END
};
static const struct YamlNode struct_CustomFunctionData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_ENUM("func", 7, enum_Functions),
YAML_UNION("fp", 48, union_anonymous_0_elmts, select_custom_fn),
YAML_UNSIGNED( "active", 8 ),
YAML_END
};
static const struct YamlNode struct_string_24[] = {
YAML_IDX,
YAML_STRING("val", 3),
YAML_END
};
static const struct YamlNode union_ZoneOptionValue_elmts[] = {
YAML_UNSIGNED( "unsignedValue", 32 ),
YAML_SIGNED( "signedValue", 32 ),
YAML_UNSIGNED( "boolValue", 32 ),
YAML_STRING("stringValue", 8),
YAML_END
};
static const struct YamlNode struct_ZoneOptionValueTyped[] = {
YAML_IDX,
YAML_ENUM("type", 32, enum_ZoneOptionValueEnum),
YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov),
YAML_END
};
static const struct YamlNode struct_ThemeBase__PersistentData[] = {
YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "version", 8 ),
YAML_UNSIGNED( "variant", 16 ),
YAML_ARRAY("calib", 48, 15, struct_CalibData, NULL),
YAML_UNSIGNED( "chkSum", 16 ),
YAML_UNSIGNED( "vBatWarn", 8 ),
YAML_SIGNED( "txVoltageCalibration", 8 ),
YAML_UNSIGNED( "backlightMode", 3 ),
YAML_SIGNED( "antennaMode", 2 ),
YAML_UNSIGNED( "disableRtcWarning", 1 ),
YAML_PADDING( 2 ),
YAML_STRUCT("trainer", 128, struct_TrainerData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "fai", 1 ),
YAML_SIGNED( "beepMode", 2 ),
YAML_UNSIGNED( "alarmsFlash", 1 ),
YAML_UNSIGNED( "disableMemoryWarning", 1 ),
YAML_UNSIGNED( "disableAlarmWarning", 1 ),
YAML_UNSIGNED( "stickMode", 2 ),
YAML_SIGNED( "timezone", 5 ),
YAML_UNSIGNED( "adjustRTC", 1 ),
YAML_UNSIGNED( "inactivityTimer", 8 ),
YAML_UNSIGNED( "telemetryBaudrate", 3 ),
YAML_UNSIGNED( "splashSpares", 3 ),
YAML_SIGNED( "hapticMode", 2 ),
YAML_SIGNED( "switchesDelay", 8 ),
YAML_UNSIGNED( "lightAutoOff", 8 ),
YAML_UNSIGNED( "templateSetup", 8 ),
YAML_SIGNED( "PPM_Multiplier", 8 ),
YAML_SIGNED( "hapticLength", 8 ),
YAML_SIGNED( "beepLength", 3 ),
YAML_SIGNED( "hapticStrength", 3 ),
YAML_UNSIGNED( "gpsFormat", 1 ),
YAML_UNSIGNED( "unexpectedShutdown", 1 ),
YAML_UNSIGNED( "speakerPitch", 8 ),
YAML_SIGNED( "speakerVolume", 8 ),
YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ),
YAML_SIGNED_CUST( "vBatMax", 8, r_vbat_max, w_vbat_max ),
YAML_UNSIGNED( "backlightBright", 8 ),
YAML_UNSIGNED( "globalTimer", 32 ),
YAML_UNSIGNED( "bluetoothBaudrate", 4 ),
YAML_UNSIGNED( "bluetoothMode", 4 ),
YAML_UNSIGNED( "countryCode", 2 ),
YAML_SIGNED( "pwrOnSpeed", 3 ),
YAML_SIGNED( "pwrOffSpeed", 3 ),
YAML_UNSIGNED( "imperial", 1 ),
YAML_UNSIGNED( "jitterFilter", 1 ),
YAML_UNSIGNED( "disableRssiPoweroffAlarm", 1 ),
YAML_UNSIGNED( "USBMode", 2 ),
YAML_UNSIGNED( "jackMode", 2 ),
YAML_PADDING( 1 ),
YAML_STRING("ttsLanguage", 2),
YAML_SIGNED( "beepVolume", 4 ),
YAML_SIGNED( "wavVolume", 4 ),
YAML_SIGNED( "varioVolume", 4 ),
YAML_SIGNED( "backgroundVolume", 4 ),
YAML_SIGNED( "varioPitch", 8 ),
YAML_SIGNED( "varioRange", 8 ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_UNSIGNED( "auxSerialMode", 8 ),
YAML_ARRAY("switchConfig", 2, 16, struct_switchConfig, nullptr),
YAML_ARRAY("potsConfig", 2, 8, struct_potConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 8, struct_sliderConfig, nullptr),
YAML_ARRAY("switchNames", 24, 10, struct_string_24, NULL),
YAML_ARRAY("anaNames", 24, 13, struct_string_24, NULL),
YAML_STRING("currModelFilename", 17),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "blOffBright", 7 ),
YAML_STRING("bluetoothName", 10),
YAML_STRING("themeName", 8),
YAML_STRUCT("themeData", 480, struct_ThemeBase__PersistentData, NULL),
YAML_STRING("ownerRegistrationID", 8),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
YAML_IDX,
YAML_UNSIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
YAML_IDX,
YAML_UNSIGNED( "start", 22 ),
YAML_SIGNED( "swtch", 10 ),
YAML_SIGNED( "value", 22 ),
YAML_UNSIGNED( "mode", 3 ),
YAML_UNSIGNED( "countdownBeep", 2 ),
YAML_UNSIGNED( "minuteBeep", 1 ),
YAML_UNSIGNED( "persistent", 2 ),
YAML_SIGNED( "countdownStart", 2 ),
YAML_STRING("name", 8),
YAML_END
};
static const struct YamlNode struct_CurveRef[] = {
YAML_UNSIGNED( "type", 8 ),
YAML_SIGNED( "value", 8 ),
YAML_END
};
static const struct YamlNode struct_MixData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "weight", 11, in_read_weight, in_write_weight ),
YAML_UNSIGNED( "destCh", 5 ),
YAML_UNSIGNED_CUST( "srcRaw", 10, r_mixSrcRaw, w_mixSrcRaw ),
YAML_UNSIGNED( "carryTrim", 1 ),
YAML_UNSIGNED( "mixWarn", 2 ),
YAML_UNSIGNED( "mltpx", 2 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "offset", 14 ),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_UNSIGNED( "flightModes", 9 ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_UNSIGNED( "delayUp", 8 ),
YAML_UNSIGNED( "delayDown", 8 ),
YAML_UNSIGNED( "speedUp", 8 ),
YAML_UNSIGNED( "speedDown", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_LimitData[] = {
YAML_IDX,
YAML_SIGNED( "min", 11 ),
YAML_SIGNED( "max", 11 ),
YAML_SIGNED( "ppmCenter", 10 ),
YAML_SIGNED( "offset", 11 ),
YAML_UNSIGNED( "symetrical", 1 ),
YAML_UNSIGNED( "revert", 1 ),
YAML_PADDING( 3 ),
YAML_SIGNED( "curve", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_ExpoData[] = {
YAML_IDX,
YAML_UNSIGNED( "mode", 2 ),
YAML_UNSIGNED( "scale", 14 ),
YAML_ENUM("srcRaw", 10, enum_MixSources),
YAML_SIGNED( "carryTrim", 6 ),
YAML_UNSIGNED( "chn", 5 ),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_UNSIGNED( "flightModes", 9 ),
YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ),
YAML_PADDING( 1 ),
YAML_STRING("name", 6),
YAML_SIGNED( "offset", 8 ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_END
};
static const struct YamlNode struct_CurveHeader[] = {
YAML_IDX,
YAML_UNSIGNED( "type", 1 ),
YAML_UNSIGNED( "smooth", 1 ),
YAML_SIGNED( "points", 6 ),
YAML_STRING("name", 3),
YAML_END
};
static const struct YamlNode struct_signed_8[] = {
YAML_IDX,
YAML_SIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_IDX,
YAML_ENUM("func", 8, enum_LogicalSwitchesFunctions),
YAML_SIGNED( "v1", 10 ),
YAML_SIGNED( "v3", 10 ),
YAML_SIGNED( "andsw", 9 ),
YAML_UNSIGNED( "andswtype", 1 ),
YAML_PADDING( 2 ),
YAML_SIGNED( "v2", 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
YAML_END
};
static const struct YamlNode struct_SwashRingData[] = {
YAML_UNSIGNED( "type", 8 ),
YAML_UNSIGNED( "value", 8 ),
YAML_UNSIGNED( "collectiveSource", 8 ),
YAML_UNSIGNED( "aileronSource", 8 ),
YAML_UNSIGNED( "elevatorSource", 8 ),
YAML_SIGNED( "collectiveWeight", 8 ),
YAML_SIGNED( "aileronWeight", 8 ),
YAML_SIGNED( "elevatorWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_trim_t[] = {
YAML_IDX,
YAML_SIGNED( "value", 11 ),
YAML_UNSIGNED( "mode", 5 ),
YAML_END
};
static const struct YamlNode struct_FlightModeData[] = {
YAML_IDX,
YAML_ARRAY("trim", 16, 6, struct_trim_t, NULL),
YAML_STRING("name", 10),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 7 ),
YAML_UNSIGNED( "fadeIn", 8 ),
YAML_UNSIGNED( "fadeOut", 8 ),
YAML_ARRAY("gvars", 16, 9, struct_signed_16, gvar_is_active),
YAML_END
};
static const struct YamlNode struct_GVarData[] = {
YAML_IDX,
YAML_STRING("name", 3),
YAML_UNSIGNED( "min", 12 ),
YAML_UNSIGNED( "max", 12 ),
YAML_UNSIGNED( "popup", 1 ),
YAML_UNSIGNED( "prec", 1 ),
YAML_UNSIGNED( "unit", 2 ),
YAML_PADDING( 4 ),
YAML_END
};
static const struct YamlNode struct_VarioData[] = {
YAML_UNSIGNED( "source", 7 ),
YAML_UNSIGNED( "centerSilent", 1 ),
YAML_SIGNED( "centerMax", 8 ),
YAML_SIGNED( "centerMin", 8 ),
YAML_SIGNED( "min", 8 ),
YAML_SIGNED( "max", 8 ),
YAML_END
};
static const struct YamlNode struct_RssiAlarmData[] = {
YAML_SIGNED( "disabled", 1 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "warning", 6 ),
YAML_PADDING( 2 ),
YAML_SIGNED( "critical", 6 ),
YAML_END
};
static const struct YamlNode struct_anonymous_5[] = {
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_UNSIGNED( "outputType", 1 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_6[] = {
YAML_UNSIGNED( "rfProtocolExtra", 2 ),
YAML_PADDING( 3 ),
YAML_UNSIGNED( "customProto", 1 ),
YAML_UNSIGNED( "autoBindMode", 1 ),
YAML_UNSIGNED( "lowPowerMode", 1 ),
YAML_SIGNED( "optionValue", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_7[] = {
YAML_UNSIGNED( "power", 2 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "receiverTelemetryOff", 1 ),
YAML_UNSIGNED( "receiverHigherChannels", 1 ),
YAML_SIGNED( "antennaMode", 2 ),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_8[] = {
YAML_PADDING( 6 ),
YAML_UNSIGNED( "noninverted", 1 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "refreshRate", 8 ),
YAML_END
};
static const struct YamlNode struct_string_64[] = {
YAML_IDX,
YAML_STRING("val", 8),
YAML_END
};
static const struct YamlNode struct_anonymous_9[] = {
YAML_UNSIGNED( "receivers", 8 ),
YAML_ARRAY("receiverName", 64, 3, struct_string_64, NULL),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_ARRAY("raw", 8, 25, struct_unsigned_8, NULL),
YAML_STRUCT("ppm", 16, struct_anonymous_5, NULL),
YAML_STRUCT("multi", 16, struct_anonymous_6, NULL),
YAML_STRUCT("pxx", 16, struct_anonymous_7, NULL),
YAML_STRUCT("sbus", 16, struct_anonymous_8, NULL),
YAML_STRUCT("pxx2", 200, struct_anonymous_9, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
YAML_IDX,
YAML_ENUM("type", 4, enum_ModuleType),
YAML_SIGNED( "rfProtocol", 4 ),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED( "channelsCount", 8 ),
YAML_UNSIGNED( "failsafeMode", 4 ),
YAML_UNSIGNED( "subType", 3 ),
YAML_UNSIGNED( "invertedSerial", 1 ),
YAML_UNION("mod", 200, union_anonymous_4_elmts, select_mod_type),
YAML_END
};
static const struct YamlNode struct_TrainerModuleData[] = {
YAML_UNSIGNED( "mode", 3 ),
YAML_PADDING( 5 ),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED( "channelsCount", 8 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_PADDING( 1 ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput_elmts[] = {
YAML_SIGNED( "value", 16 ),
YAML_UNSIGNED( "source", 16 ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput[] = {
YAML_IDX,
YAML_UNION("u", 16, union_ScriptDataInput_elmts, select_script_input),
YAML_END
};
static const struct YamlNode struct_ScriptData[] = {
YAML_IDX,
YAML_STRING("file", 6),
YAML_STRING("name", 6),
YAML_ARRAY("inputs", 16, 6, union_ScriptDataInput, NULL),
YAML_END
};
static const struct YamlNode struct_string_32[] = {
YAML_IDX,
YAML_STRING("val", 4),
YAML_END
};
static const struct YamlNode union_anonymous_10_elmts[] = {
YAML_UNSIGNED( "id", 16 ),
YAML_UNSIGNED( "persistentValue", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_12[] = {
YAML_UNSIGNED( "physID", 5 ),
YAML_UNSIGNED( "rxIndex", 3 ),
YAML_END
};
static const struct YamlNode union_anonymous_11_elmts[] = {
YAML_STRUCT("frskyInstance", 8, struct_anonymous_12, NULL),
YAML_UNSIGNED( "instance", 8 ),
YAML_UNSIGNED( "formula", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_14[] = {
YAML_UNSIGNED( "ratio", 16 ),
YAML_SIGNED( "offset", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_15[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_UNSIGNED( "index", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_16[] = {
YAML_ARRAY("sources", 8, 4, struct_signed_8, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_17[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_PADDING( 24 ),
YAML_END
};
static const struct YamlNode struct_anonymous_18[] = {
YAML_UNSIGNED( "gps", 8 ),
YAML_UNSIGNED( "alt", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode union_anonymous_13_elmts[] = {
YAML_STRUCT("custom", 32, struct_anonymous_14, NULL),
YAML_STRUCT("cell", 32, struct_anonymous_15, NULL),
YAML_STRUCT("calc", 32, struct_anonymous_16, NULL),
YAML_STRUCT("consumption", 32, struct_anonymous_17, NULL),
YAML_STRUCT("dist", 32, struct_anonymous_18, NULL),
YAML_UNSIGNED( "param", 32 ),
YAML_END
};
static const struct YamlNode struct_TelemetrySensor[] = {
YAML_IDX,
YAML_UNION("id1", 16, union_anonymous_10_elmts, select_id1),
YAML_UNION("id2", 8, union_anonymous_11_elmts, select_id2),
YAML_STRING("label", 4),
YAML_UNSIGNED( "subId", 8 ),
YAML_UNSIGNED( "type", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "unit", 6 ),
YAML_UNSIGNED( "prec", 2 ),
YAML_UNSIGNED( "autoOffset", 1 ),
YAML_UNSIGNED( "filter", 1 ),
YAML_UNSIGNED( "logs", 1 ),
YAML_UNSIGNED( "persistent", 1 ),
YAML_UNSIGNED( "onlyPositive", 1 ),
YAML_PADDING( 1 ),
YAML_UNION("cfg", 32, union_anonymous_13_elmts, select_sensor_cfg),
YAML_END
};
static const struct YamlNode struct_Widget__PersistentData[] = {
YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_ZonePersistentData[] = {
YAML_IDX,
YAML_STRING("widgetName", 10),
YAML_STRUCT("widgetData", 480, struct_Widget__PersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_Layout__PersistentData[] = {
YAML_ARRAY("zones", 576, 10, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 96, 10, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_CustomScreenData[] = {
YAML_IDX,
YAML_STRING("layoutName", 10),
YAML_STRUCT("layoutData", 6720, struct_Layout__PersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_Topbar__PersistentData[] = {
YAML_ARRAY("zones", 576, 4, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 128, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
YAML_UNSIGNED( "noGlobalFunctions", 1 ),
YAML_UNSIGNED( "displayTrims", 2 ),
YAML_UNSIGNED( "ignoreSensorIds", 1 ),
YAML_SIGNED( "trimInc", 3 ),
YAML_UNSIGNED( "disableThrottleWarning", 1 ),
YAML_UNSIGNED( "displayChecklist", 1 ),
YAML_UNSIGNED( "extendedLimits", 1 ),
YAML_UNSIGNED( "extendedTrims", 1 ),
YAML_UNSIGNED( "throttleReversed", 1 ),
YAML_UNSIGNED( "beepANACenter", 16 ),
YAML_ARRAY("mixData", 160, 64, struct_MixData, NULL),
YAML_ARRAY("limitData", 104, 32, struct_LimitData, NULL),
YAML_ARRAY("expoData", 136, 64, struct_ExpoData, NULL),
YAML_ARRAY("curves", 32, 32, struct_CurveHeader, NULL),
YAML_ARRAY("points", 8, 512, struct_signed_8, NULL),
YAML_ARRAY("logicalSw", 72, 64, struct_LogicalSwitchData, NULL),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_STRUCT("swashR", 64, struct_SwashRingData, NULL),
YAML_ARRAY("flightModeData", 352, 9, struct_FlightModeData, fmd_is_active),
YAML_UNSIGNED( "thrTraceSrc", 8 ),
YAML_UNSIGNED( "switchWarningState", 32 ),
YAML_ARRAY("gvars", 56, 9, struct_GVarData, NULL),
YAML_STRUCT("varioData", 40, struct_VarioData, NULL),
YAML_UNSIGNED( "rssiSource", 8 ),
YAML_STRUCT("rssiAlarms", 16, struct_RssiAlarmData, NULL),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "potsWarnMode", 2 ),
YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL),
YAML_ARRAY("failsafeChannels", 16, 32, struct_signed_16, NULL),
YAML_STRUCT("trainerData", 40, struct_TrainerModuleData, NULL),
YAML_ARRAY("scriptsData", 192, 9, struct_ScriptData, NULL),
YAML_ARRAY("inputNames", 32, 32, struct_string_32, NULL),
YAML_UNSIGNED( "potsWarnEnabled", 8 ),
YAML_ARRAY("potsWarnPosition", 8, 9, struct_signed_8, NULL),
YAML_ARRAY("telemetrySensors", 112, 60, struct_TelemetrySensor, NULL),
YAML_ARRAY("screenData", 6800, 5, struct_CustomScreenData, NULL),
YAML_STRUCT("topbarData", 2400, struct_Topbar__PersistentData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_END
};
#define MAX_RADIODATA_MODELDATA_STR_LEN 24
static const struct YamlNode __RadioData_root_node = YAML_ROOT( struct_RadioData );
const YamlNode* get_radiodata_nodes()
{
return &__RadioData_root_node;
}
static const struct YamlNode __ModelData_root_node = YAML_ROOT( struct_ModelData );
const YamlNode* get_modeldata_nodes()
{
return &__ModelData_root_node;
}

View file

@ -0,0 +1,771 @@
// generated by generate_yaml.py
//
// Enums first
//
const struct YamlIdStr enum_Functions[] = {
{ FUNC_OVERRIDE_CHANNEL, "OVERRIDE_CHANNEL" },
{ FUNC_TRAINER, "TRAINER" },
{ FUNC_INSTANT_TRIM, "INSTANT_TRIM" },
{ FUNC_RESET, "RESET" },
{ FUNC_SET_TIMER, "SET_TIMER" },
{ FUNC_ADJUST_GVAR, "ADJUST_GVAR" },
{ FUNC_VOLUME, "VOLUME" },
{ FUNC_SET_FAILSAFE, "SET_FAILSAFE" },
{ FUNC_RANGECHECK, "RANGECHECK" },
{ FUNC_BIND, "BIND" },
{ FUNC_FIRST_WITHOUT_ENABLE, "FIRST_WITHOUT_ENABLE" },
{ FUNC_PLAY_SOUND, "PLAY_SOUND" },
{ FUNC_PLAY_TRACK, "PLAY_TRACK" },
{ FUNC_PLAY_VALUE, "PLAY_VALUE" },
{ FUNC_RESERVE4, "RESERVE4" },
{ FUNC_PLAY_SCRIPT, "PLAY_SCRIPT" },
{ FUNC_RESERVE5, "RESERVE5" },
{ FUNC_BACKGND_MUSIC, "BACKGND_MUSIC" },
{ FUNC_BACKGND_MUSIC_PAUSE, "BACKGND_MUSIC_PAUSE" },
{ FUNC_VARIO, "VARIO" },
{ FUNC_HAPTIC, "HAPTIC" },
{ FUNC_LOGS, "LOGS" },
{ FUNC_BACKLIGHT, "BACKLIGHT" },
{ FUNC_SCREENSHOT, "SCREENSHOT" },
{ FUNC_MAX, "MAX" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
{ ZOV_Bool, "Bool" },
{ ZOV_String, "String" },
{ 0, NULL }
};
const struct YamlIdStr enum_MixSources[] = {
{ MIXSRC_NONE, "NONE" },
{ MIXSRC_Rud, "Rud" },
{ MIXSRC_Ele, "Ele" },
{ MIXSRC_Thr, "Thr" },
{ MIXSRC_Ail, "Ail" },
{ MIXSRC_S1, "S1" },
{ MIXSRC_6POS, "6POS" },
{ MIXSRC_S2, "S2" },
{ MIXSRC_S3, "S3" },
{ MIXSRC_S4, "S4" },
{ MIXSRC_LS, "LS" },
{ MIXSRC_RS, "RS" },
{ MIXSRC_MOUSE1, "MOUSE1" },
{ MIXSRC_MOUSE2, "MOUSE2" },
{ MIXSRC_MAX, "MAX" },
{ MIXSRC_CYC1, "CYC1" },
{ MIXSRC_CYC2, "CYC2" },
{ MIXSRC_CYC3, "CYC3" },
{ MIXSRC_TrimRud, "TrimRud" },
{ MIXSRC_TrimEle, "TrimEle" },
{ MIXSRC_TrimThr, "TrimThr" },
{ MIXSRC_TrimAil, "TrimAil" },
{ MIXSRC_TrimT5, "TrimT5" },
{ MIXSRC_TrimT6, "TrimT6" },
{ MIXSRC_SA, "SA" },
{ MIXSRC_SB, "SB" },
{ MIXSRC_SC, "SC" },
{ MIXSRC_SD, "SD" },
{ MIXSRC_SE, "SE" },
{ MIXSRC_SF, "SF" },
{ MIXSRC_SG, "SG" },
{ MIXSRC_SH, "SH" },
{ MIXSRC_SI, "SI" },
{ MIXSRC_SJ, "SJ" },
{ MIXSRC_SW1, "SW1" },
{ MIXSRC_CH1, "CH1" },
{ MIXSRC_CH2, "CH2" },
{ MIXSRC_CH3, "CH3" },
{ MIXSRC_CH4, "CH4" },
{ MIXSRC_CH5, "CH5" },
{ MIXSRC_CH6, "CH6" },
{ MIXSRC_CH7, "CH7" },
{ MIXSRC_CH8, "CH8" },
{ MIXSRC_CH9, "CH9" },
{ MIXSRC_CH10, "CH10" },
{ MIXSRC_CH11, "CH11" },
{ MIXSRC_CH12, "CH12" },
{ MIXSRC_CH13, "CH13" },
{ MIXSRC_CH14, "CH14" },
{ MIXSRC_CH15, "CH15" },
{ MIXSRC_CH16, "CH16" },
{ MIXSRC_GVAR1, "GVAR1" },
{ MIXSRC_TX_VOLTAGE, "TX_VOLTAGE" },
{ MIXSRC_TX_TIME, "TX_TIME" },
{ MIXSRC_TX_GPS, "TX_GPS" },
{ MIXSRC_TIMER1, "TIMER1" },
{ MIXSRC_TIMER2, "TIMER2" },
{ MIXSRC_TIMER3, "TIMER3" },
{ 0, NULL }
};
const struct YamlIdStr enum_LogicalSwitchesFunctions[] = {
{ LS_FUNC_NONE, "FUNC_NONE" },
{ LS_FUNC_VEQUAL, "FUNC_VEQUAL" },
{ LS_FUNC_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL" },
{ LS_FUNC_VPOS, "FUNC_VPOS" },
{ LS_FUNC_VNEG, "FUNC_VNEG" },
{ LS_FUNC_RANGE, "FUNC_RANGE" },
{ LS_FUNC_APOS, "FUNC_APOS" },
{ LS_FUNC_ANEG, "FUNC_ANEG" },
{ LS_FUNC_AND, "FUNC_AND" },
{ LS_FUNC_OR, "FUNC_OR" },
{ LS_FUNC_XOR, "FUNC_XOR" },
{ LS_FUNC_EDGE, "FUNC_EDGE" },
{ LS_FUNC_EQUAL, "FUNC_EQUAL" },
{ LS_FUNC_GREATER, "FUNC_GREATER" },
{ LS_FUNC_LESS, "FUNC_LESS" },
{ LS_FUNC_DIFFEGREATER, "FUNC_DIFFEGREATER" },
{ LS_FUNC_ADIFFEGREATER, "FUNC_ADIFFEGREATER" },
{ LS_FUNC_TIMER, "FUNC_TIMER" },
{ LS_FUNC_STICKY, "FUNC_STICKY" },
{ LS_FUNC_COUNT, "FUNC_COUNT" },
{ LS_FUNC_MAX, "FUNC_MAX" },
{ 0, NULL }
};
const struct YamlIdStr enum_SwitchSources[] = {
{ SWSRC_NONE, "NONE" },
{ SWSRC_SA0, "SA0" },
{ SWSRC_SA1, "SA1" },
{ SWSRC_SA2, "SA2" },
{ SWSRC_SB0, "SB0" },
{ SWSRC_SB1, "SB1" },
{ SWSRC_SB2, "SB2" },
{ SWSRC_SC0, "SC0" },
{ SWSRC_SC1, "SC1" },
{ SWSRC_SC2, "SC2" },
{ SWSRC_SD0, "SD0" },
{ SWSRC_SD1, "SD1" },
{ SWSRC_SD2, "SD2" },
{ SWSRC_SE0, "SE0" },
{ SWSRC_SE1, "SE1" },
{ SWSRC_SE2, "SE2" },
{ SWSRC_SF0, "SF0" },
{ SWSRC_SF1, "SF1" },
{ SWSRC_SF2, "SF2" },
{ SWSRC_SG0, "SG0" },
{ SWSRC_SG1, "SG1" },
{ SWSRC_SG2, "SG2" },
{ SWSRC_SH0, "SH0" },
{ SWSRC_SH1, "SH1" },
{ SWSRC_SH2, "SH2" },
{ SWSRC_SI0, "SI0" },
{ SWSRC_SI1, "SI1" },
{ SWSRC_SI2, "SI2" },
{ SWSRC_SJ0, "SJ0" },
{ SWSRC_SJ1, "SJ1" },
{ SWSRC_SJ2, "SJ2" },
{ SWSRC_TrimRudLeft, "TrimRudLeft" },
{ SWSRC_TrimRudRight, "TrimRudRight" },
{ SWSRC_TrimEleDown, "TrimEleDown" },
{ SWSRC_TrimEleUp, "TrimEleUp" },
{ SWSRC_TrimThrDown, "TrimThrDown" },
{ SWSRC_TrimThrUp, "TrimThrUp" },
{ SWSRC_TrimAilLeft, "TrimAilLeft" },
{ SWSRC_TrimAilRight, "TrimAilRight" },
{ SWSRC_TrimT5Down, "TrimT5Down" },
{ SWSRC_TrimT5Up, "TrimT5Up" },
{ SWSRC_TrimT6Down, "TrimT6Down" },
{ SWSRC_TrimT6Up, "TrimT6Up" },
{ SWSRC_SW1, "SW1" },
{ SWSRC_SW2, "SW2" },
{ SWSRC_ON, "ON" },
{ SWSRC_ONE, "ONE" },
{ SWSRC_TELEMETRY_STREAMING, "TELEMETRY_STREAMING" },
{ SWSRC_RADIO_ACTIVITY, "RADIO_ACTIVITY" },
{ SWSRC_OFF, "OFF" },
{ 0, NULL }
};
const struct YamlIdStr enum_ModuleType[] = {
{ MODULE_TYPE_NONE, "TYPE_NONE" },
{ MODULE_TYPE_PPM, "TYPE_PPM" },
{ MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" },
{ MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" },
{ MODULE_TYPE_DSM2, "TYPE_DSM2" },
{ MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" },
{ MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" },
{ MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" },
{ MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" },
{ MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" },
{ MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" },
{ MODULE_TYPE_R9M_LITE_PRO_PXX1, "TYPE_R9M_LITE_PRO_PXX1" },
{ MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" },
{ MODULE_TYPE_SBUS, "TYPE_SBUS" },
{ MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" },
{ MODULE_TYPE_FLYSKY, "TYPE_FLYSKY" },
{ MODULE_TYPE_COUNT, "TYPE_COUNT" },
{ MODULE_TYPE_MAX, "TYPE_MAX" },
{ 0, NULL }
};
//
// Structs last
//
static const struct YamlNode struct_CalibData[] = {
YAML_IDX,
YAML_SIGNED( "mid", 16 ),
YAML_SIGNED( "spanNeg", 16 ),
YAML_SIGNED( "spanPos", 16 ),
YAML_END
};
static const struct YamlNode struct_signed_16[] = {
YAML_IDX,
YAML_SIGNED( "val", 16 ),
YAML_END
};
static const struct YamlNode struct_TrainerMix[] = {
YAML_IDX,
YAML_UNSIGNED( "srcChn", 6 ),
YAML_UNSIGNED( "mode", 2 ),
YAML_SIGNED( "studWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_TrainerData[] = {
YAML_ARRAY("calib", 16, 4, struct_signed_16, NULL),
YAML_ARRAY("mix", 16, 4, struct_TrainerMix, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_1[] = {
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_anonymous_2[] = {
YAML_SIGNED( "val", 16 ),
YAML_UNSIGNED( "mode", 8 ),
YAML_UNSIGNED( "param", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_3[] = {
YAML_SIGNED( "val1", 32 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode union_anonymous_0_elmts[] = {
YAML_STRUCT("play", 48, struct_anonymous_1, NULL),
YAML_STRUCT("all", 48, struct_anonymous_2, NULL),
YAML_STRUCT("clear", 48, struct_anonymous_3, NULL),
YAML_END
};
static const struct YamlNode struct_CustomFunctionData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_ENUM("func", 7, enum_Functions),
YAML_UNION("fp", 48, union_anonymous_0_elmts, select_custom_fn),
YAML_UNSIGNED( "active", 8 ),
YAML_END
};
static const struct YamlNode struct_string_24[] = {
YAML_IDX,
YAML_STRING("val", 3),
YAML_END
};
static const struct YamlNode union_ZoneOptionValue_elmts[] = {
YAML_UNSIGNED( "unsignedValue", 32 ),
YAML_SIGNED( "signedValue", 32 ),
YAML_UNSIGNED( "boolValue", 32 ),
YAML_STRING("stringValue", 8),
YAML_END
};
static const struct YamlNode struct_ZoneOptionValueTyped[] = {
YAML_IDX,
YAML_ENUM("type", 32, enum_ZoneOptionValueEnum),
YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov),
YAML_END
};
static const struct YamlNode struct_ThemeBase__PersistentData[] = {
YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "version", 8 ),
YAML_UNSIGNED( "variant", 16 ),
YAML_ARRAY("calib", 48, 15, struct_CalibData, NULL),
YAML_UNSIGNED( "chkSum", 16 ),
YAML_UNSIGNED( "vBatWarn", 8 ),
YAML_SIGNED( "txVoltageCalibration", 8 ),
YAML_UNSIGNED( "backlightMode", 3 ),
YAML_SIGNED( "antennaMode", 2 ),
YAML_UNSIGNED( "disableRtcWarning", 1 ),
YAML_PADDING( 2 ),
YAML_STRUCT("trainer", 128, struct_TrainerData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "fai", 1 ),
YAML_SIGNED( "beepMode", 2 ),
YAML_UNSIGNED( "alarmsFlash", 1 ),
YAML_UNSIGNED( "disableMemoryWarning", 1 ),
YAML_UNSIGNED( "disableAlarmWarning", 1 ),
YAML_UNSIGNED( "stickMode", 2 ),
YAML_SIGNED( "timezone", 5 ),
YAML_UNSIGNED( "adjustRTC", 1 ),
YAML_UNSIGNED( "inactivityTimer", 8 ),
YAML_UNSIGNED( "telemetryBaudrate", 3 ),
YAML_UNSIGNED( "splashSpares", 3 ),
YAML_SIGNED( "hapticMode", 2 ),
YAML_SIGNED( "switchesDelay", 8 ),
YAML_UNSIGNED( "lightAutoOff", 8 ),
YAML_UNSIGNED( "templateSetup", 8 ),
YAML_SIGNED( "PPM_Multiplier", 8 ),
YAML_SIGNED( "hapticLength", 8 ),
YAML_SIGNED( "beepLength", 3 ),
YAML_SIGNED( "hapticStrength", 3 ),
YAML_UNSIGNED( "gpsFormat", 1 ),
YAML_UNSIGNED( "unexpectedShutdown", 1 ),
YAML_UNSIGNED( "speakerPitch", 8 ),
YAML_SIGNED( "speakerVolume", 8 ),
YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ),
YAML_SIGNED_CUST( "vBatMax", 8, r_vbat_max, w_vbat_max ),
YAML_UNSIGNED( "backlightBright", 8 ),
YAML_UNSIGNED( "globalTimer", 32 ),
YAML_UNSIGNED( "bluetoothBaudrate", 4 ),
YAML_UNSIGNED( "bluetoothMode", 4 ),
YAML_UNSIGNED( "countryCode", 2 ),
YAML_SIGNED( "pwrOnSpeed", 3 ),
YAML_SIGNED( "pwrOffSpeed", 3 ),
YAML_UNSIGNED( "imperial", 1 ),
YAML_UNSIGNED( "jitterFilter", 1 ),
YAML_UNSIGNED( "disableRssiPoweroffAlarm", 1 ),
YAML_UNSIGNED( "USBMode", 2 ),
YAML_UNSIGNED( "jackMode", 2 ),
YAML_PADDING( 1 ),
YAML_STRING("ttsLanguage", 2),
YAML_SIGNED( "beepVolume", 4 ),
YAML_SIGNED( "wavVolume", 4 ),
YAML_SIGNED( "varioVolume", 4 ),
YAML_SIGNED( "backgroundVolume", 4 ),
YAML_SIGNED( "varioPitch", 8 ),
YAML_SIGNED( "varioRange", 8 ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_UNSIGNED( "auxSerialMode", 8 ),
YAML_ARRAY("switchConfig", 2, 16, struct_switchConfig, nullptr),
YAML_ARRAY("potsConfig", 2, 8, struct_potConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 8, struct_sliderConfig, nullptr),
YAML_ARRAY("switchNames", 24, 10, struct_string_24, NULL),
YAML_ARRAY("anaNames", 24, 13, struct_string_24, NULL),
YAML_STRING("currModelFilename", 17),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "blOffBright", 7 ),
YAML_STRING("bluetoothName", 10),
YAML_STRING("themeName", 8),
YAML_STRUCT("themeData", 480, struct_ThemeBase__PersistentData, NULL),
YAML_STRING("ownerRegistrationID", 8),
YAML_END
};
static const struct YamlNode struct_unsigned_8[] = {
YAML_IDX,
YAML_UNSIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_ModelHeader[] = {
YAML_STRING("name", 15),
YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL),
YAML_STRING("bitmap", 14),
YAML_END
};
static const struct YamlNode struct_TimerData[] = {
YAML_IDX,
YAML_UNSIGNED( "start", 22 ),
YAML_SIGNED( "swtch", 10 ),
YAML_SIGNED( "value", 22 ),
YAML_UNSIGNED( "mode", 3 ),
YAML_UNSIGNED( "countdownBeep", 2 ),
YAML_UNSIGNED( "minuteBeep", 1 ),
YAML_UNSIGNED( "persistent", 2 ),
YAML_SIGNED( "countdownStart", 2 ),
YAML_STRING("name", 8),
YAML_END
};
static const struct YamlNode struct_CurveRef[] = {
YAML_UNSIGNED( "type", 8 ),
YAML_SIGNED( "value", 8 ),
YAML_END
};
static const struct YamlNode struct_MixData[] = {
YAML_IDX,
YAML_SIGNED_CUST( "weight", 11, in_read_weight, in_write_weight ),
YAML_UNSIGNED( "destCh", 5 ),
YAML_UNSIGNED_CUST( "srcRaw", 10, r_mixSrcRaw, w_mixSrcRaw ),
YAML_UNSIGNED( "carryTrim", 1 ),
YAML_UNSIGNED( "mixWarn", 2 ),
YAML_UNSIGNED( "mltpx", 2 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "offset", 14 ),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_UNSIGNED( "flightModes", 9 ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_UNSIGNED( "delayUp", 8 ),
YAML_UNSIGNED( "delayDown", 8 ),
YAML_UNSIGNED( "speedUp", 8 ),
YAML_UNSIGNED( "speedDown", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_LimitData[] = {
YAML_IDX,
YAML_SIGNED( "min", 11 ),
YAML_SIGNED( "max", 11 ),
YAML_SIGNED( "ppmCenter", 10 ),
YAML_SIGNED( "offset", 11 ),
YAML_UNSIGNED( "symetrical", 1 ),
YAML_UNSIGNED( "revert", 1 ),
YAML_PADDING( 3 ),
YAML_SIGNED( "curve", 8 ),
YAML_STRING("name", 6),
YAML_END
};
static const struct YamlNode struct_ExpoData[] = {
YAML_IDX,
YAML_UNSIGNED( "mode", 2 ),
YAML_UNSIGNED( "scale", 14 ),
YAML_ENUM("srcRaw", 10, enum_MixSources),
YAML_SIGNED( "carryTrim", 6 ),
YAML_UNSIGNED( "chn", 5 ),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_UNSIGNED( "flightModes", 9 ),
YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ),
YAML_PADDING( 1 ),
YAML_STRING("name", 6),
YAML_SIGNED( "offset", 8 ),
YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
YAML_END
};
static const struct YamlNode struct_CurveHeader[] = {
YAML_IDX,
YAML_UNSIGNED( "type", 1 ),
YAML_UNSIGNED( "smooth", 1 ),
YAML_SIGNED( "points", 6 ),
YAML_STRING("name", 3),
YAML_END
};
static const struct YamlNode struct_signed_8[] = {
YAML_IDX,
YAML_SIGNED( "val", 8 ),
YAML_END
};
static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_IDX,
YAML_ENUM("func", 8, enum_LogicalSwitchesFunctions),
YAML_SIGNED( "v1", 10 ),
YAML_SIGNED( "v3", 10 ),
YAML_SIGNED( "andsw", 9 ),
YAML_UNSIGNED( "andswtype", 1 ),
YAML_PADDING( 2 ),
YAML_SIGNED( "v2", 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
YAML_END
};
static const struct YamlNode struct_SwashRingData[] = {
YAML_UNSIGNED( "type", 8 ),
YAML_UNSIGNED( "value", 8 ),
YAML_UNSIGNED( "collectiveSource", 8 ),
YAML_UNSIGNED( "aileronSource", 8 ),
YAML_UNSIGNED( "elevatorSource", 8 ),
YAML_SIGNED( "collectiveWeight", 8 ),
YAML_SIGNED( "aileronWeight", 8 ),
YAML_SIGNED( "elevatorWeight", 8 ),
YAML_END
};
static const struct YamlNode struct_trim_t[] = {
YAML_IDX,
YAML_SIGNED( "value", 11 ),
YAML_UNSIGNED( "mode", 5 ),
YAML_END
};
static const struct YamlNode struct_FlightModeData[] = {
YAML_IDX,
YAML_ARRAY("trim", 16, 6, struct_trim_t, NULL),
YAML_STRING("name", 10),
YAML_SIGNED_CUST( "swtch", 9, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 7 ),
YAML_UNSIGNED( "fadeIn", 8 ),
YAML_UNSIGNED( "fadeOut", 8 ),
YAML_ARRAY("gvars", 16, 9, struct_signed_16, gvar_is_active),
YAML_END
};
static const struct YamlNode struct_GVarData[] = {
YAML_IDX,
YAML_STRING("name", 3),
YAML_UNSIGNED( "min", 12 ),
YAML_UNSIGNED( "max", 12 ),
YAML_UNSIGNED( "popup", 1 ),
YAML_UNSIGNED( "prec", 1 ),
YAML_UNSIGNED( "unit", 2 ),
YAML_PADDING( 4 ),
YAML_END
};
static const struct YamlNode struct_VarioData[] = {
YAML_UNSIGNED( "source", 7 ),
YAML_UNSIGNED( "centerSilent", 1 ),
YAML_SIGNED( "centerMax", 8 ),
YAML_SIGNED( "centerMin", 8 ),
YAML_SIGNED( "min", 8 ),
YAML_SIGNED( "max", 8 ),
YAML_END
};
static const struct YamlNode struct_RssiAlarmData[] = {
YAML_SIGNED( "disabled", 1 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "warning", 6 ),
YAML_PADDING( 2 ),
YAML_SIGNED( "critical", 6 ),
YAML_END
};
static const struct YamlNode struct_anonymous_5[] = {
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_UNSIGNED( "outputType", 1 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_6[] = {
YAML_UNSIGNED( "rfProtocolExtra", 2 ),
YAML_PADDING( 3 ),
YAML_UNSIGNED( "customProto", 1 ),
YAML_UNSIGNED( "autoBindMode", 1 ),
YAML_UNSIGNED( "lowPowerMode", 1 ),
YAML_SIGNED( "optionValue", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_7[] = {
YAML_UNSIGNED( "power", 2 ),
YAML_PADDING( 2 ),
YAML_UNSIGNED( "receiverTelemetryOff", 1 ),
YAML_UNSIGNED( "receiverHigherChannels", 1 ),
YAML_SIGNED( "antennaMode", 2 ),
YAML_PADDING( 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_8[] = {
YAML_PADDING( 6 ),
YAML_UNSIGNED( "noninverted", 1 ),
YAML_PADDING( 1 ),
YAML_SIGNED( "refreshRate", 8 ),
YAML_END
};
static const struct YamlNode struct_string_64[] = {
YAML_IDX,
YAML_STRING("val", 8),
YAML_END
};
static const struct YamlNode struct_anonymous_9[] = {
YAML_UNSIGNED( "receivers", 8 ),
YAML_ARRAY("receiverName", 64, 3, struct_string_64, NULL),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_ARRAY("raw", 8, 25, struct_unsigned_8, NULL),
YAML_STRUCT("ppm", 16, struct_anonymous_5, NULL),
YAML_STRUCT("multi", 16, struct_anonymous_6, NULL),
YAML_STRUCT("pxx", 16, struct_anonymous_7, NULL),
YAML_STRUCT("sbus", 16, struct_anonymous_8, NULL),
YAML_STRUCT("pxx2", 200, struct_anonymous_9, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
YAML_IDX,
YAML_ENUM("type", 4, enum_ModuleType),
YAML_SIGNED( "rfProtocol", 4 ),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED( "channelsCount", 8 ),
YAML_UNSIGNED( "failsafeMode", 4 ),
YAML_UNSIGNED( "subType", 3 ),
YAML_UNSIGNED( "invertedSerial", 1 ),
YAML_UNION("mod", 200, union_anonymous_4_elmts, select_mod_type),
YAML_END
};
static const struct YamlNode struct_TrainerModuleData[] = {
YAML_UNSIGNED( "mode", 3 ),
YAML_PADDING( 5 ),
YAML_UNSIGNED( "channelsStart", 8 ),
YAML_SIGNED( "channelsCount", 8 ),
YAML_SIGNED( "frameLength", 8 ),
YAML_SIGNED( "delay", 6 ),
YAML_UNSIGNED( "pulsePol", 1 ),
YAML_PADDING( 1 ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput_elmts[] = {
YAML_SIGNED( "value", 16 ),
YAML_UNSIGNED( "source", 16 ),
YAML_END
};
static const struct YamlNode union_ScriptDataInput[] = {
YAML_IDX,
YAML_UNION("u", 16, union_ScriptDataInput_elmts, select_script_input),
YAML_END
};
static const struct YamlNode struct_ScriptData[] = {
YAML_IDX,
YAML_STRING("file", 6),
YAML_STRING("name", 6),
YAML_ARRAY("inputs", 16, 6, union_ScriptDataInput, NULL),
YAML_END
};
static const struct YamlNode struct_string_32[] = {
YAML_IDX,
YAML_STRING("val", 4),
YAML_END
};
static const struct YamlNode union_anonymous_10_elmts[] = {
YAML_UNSIGNED( "id", 16 ),
YAML_UNSIGNED( "persistentValue", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_12[] = {
YAML_UNSIGNED( "physID", 5 ),
YAML_UNSIGNED( "rxIndex", 3 ),
YAML_END
};
static const struct YamlNode union_anonymous_11_elmts[] = {
YAML_STRUCT("frskyInstance", 8, struct_anonymous_12, NULL),
YAML_UNSIGNED( "instance", 8 ),
YAML_UNSIGNED( "formula", 8 ),
YAML_END
};
static const struct YamlNode struct_anonymous_14[] = {
YAML_UNSIGNED( "ratio", 16 ),
YAML_SIGNED( "offset", 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_15[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_UNSIGNED( "index", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode struct_anonymous_16[] = {
YAML_ARRAY("sources", 8, 4, struct_signed_8, NULL),
YAML_END
};
static const struct YamlNode struct_anonymous_17[] = {
YAML_UNSIGNED( "source", 8 ),
YAML_PADDING( 24 ),
YAML_END
};
static const struct YamlNode struct_anonymous_18[] = {
YAML_UNSIGNED( "gps", 8 ),
YAML_UNSIGNED( "alt", 8 ),
YAML_PADDING( 16 ),
YAML_END
};
static const struct YamlNode union_anonymous_13_elmts[] = {
YAML_STRUCT("custom", 32, struct_anonymous_14, NULL),
YAML_STRUCT("cell", 32, struct_anonymous_15, NULL),
YAML_STRUCT("calc", 32, struct_anonymous_16, NULL),
YAML_STRUCT("consumption", 32, struct_anonymous_17, NULL),
YAML_STRUCT("dist", 32, struct_anonymous_18, NULL),
YAML_UNSIGNED( "param", 32 ),
YAML_END
};
static const struct YamlNode struct_TelemetrySensor[] = {
YAML_IDX,
YAML_UNION("id1", 16, union_anonymous_10_elmts, select_id1),
YAML_UNION("id2", 8, union_anonymous_11_elmts, select_id2),
YAML_STRING("label", 4),
YAML_UNSIGNED( "subId", 8 ),
YAML_UNSIGNED( "type", 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "unit", 6 ),
YAML_UNSIGNED( "prec", 2 ),
YAML_UNSIGNED( "autoOffset", 1 ),
YAML_UNSIGNED( "filter", 1 ),
YAML_UNSIGNED( "logs", 1 ),
YAML_UNSIGNED( "persistent", 1 ),
YAML_UNSIGNED( "onlyPositive", 1 ),
YAML_PADDING( 1 ),
YAML_UNION("cfg", 32, union_anonymous_13_elmts, select_sensor_cfg),
YAML_END
};
static const struct YamlNode struct_Widget__PersistentData[] = {
YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_ZonePersistentData[] = {
YAML_IDX,
YAML_STRING("widgetName", 10),
YAML_STRUCT("widgetData", 480, struct_Widget__PersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_Layout__PersistentData[] = {
YAML_ARRAY("zones", 576, 10, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 96, 10, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_CustomScreenData[] = {
YAML_IDX,
YAML_STRING("layoutName", 10),
YAML_STRUCT("layoutData", 6720, struct_Layout__PersistentData, NULL),
YAML_END
};
static const struct YamlNode struct_Topbar__PersistentData[] = {
YAML_ARRAY("zones", 576, 4, struct_ZonePersistentData, NULL),
YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
YAML_END
};
static const struct YamlNode struct_ModelData[] = {
YAML_STRUCT("header", 248, struct_ModelHeader, NULL),
YAML_ARRAY("timers", 128, 3, struct_TimerData, NULL),
YAML_UNSIGNED( "telemetryProtocol", 3 ),
YAML_UNSIGNED( "thrTrim", 1 ),
YAML_UNSIGNED( "noGlobalFunctions", 1 ),
YAML_UNSIGNED( "displayTrims", 2 ),
YAML_UNSIGNED( "ignoreSensorIds", 1 ),
YAML_SIGNED( "trimInc", 3 ),
YAML_UNSIGNED( "disableThrottleWarning", 1 ),
YAML_UNSIGNED( "displayChecklist", 1 ),
YAML_UNSIGNED( "extendedLimits", 1 ),
YAML_UNSIGNED( "extendedTrims", 1 ),
YAML_UNSIGNED( "throttleReversed", 1 ),
YAML_UNSIGNED( "beepANACenter", 16 ),
YAML_ARRAY("mixData", 160, 64, struct_MixData, NULL),
YAML_ARRAY("limitData", 104, 32, struct_LimitData, NULL),
YAML_ARRAY("expoData", 136, 64, struct_ExpoData, NULL),
YAML_ARRAY("curves", 32, 32, struct_CurveHeader, NULL),
YAML_ARRAY("points", 8, 512, struct_signed_8, NULL),
YAML_ARRAY("logicalSw", 72, 64, struct_LogicalSwitchData, NULL),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_STRUCT("swashR", 64, struct_SwashRingData, NULL),
YAML_ARRAY("flightModeData", 352, 9, struct_FlightModeData, fmd_is_active),
YAML_UNSIGNED( "thrTraceSrc", 8 ),
YAML_UNSIGNED( "switchWarningState", 32 ),
YAML_ARRAY("gvars", 56, 9, struct_GVarData, NULL),
YAML_STRUCT("varioData", 40, struct_VarioData, NULL),
YAML_UNSIGNED( "rssiSource", 8 ),
YAML_STRUCT("rssiAlarms", 16, struct_RssiAlarmData, NULL),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "potsWarnMode", 2 ),
YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL),
YAML_ARRAY("failsafeChannels", 16, 32, struct_signed_16, NULL),
YAML_STRUCT("trainerData", 40, struct_TrainerModuleData, NULL),
YAML_ARRAY("scriptsData", 192, 9, struct_ScriptData, NULL),
YAML_ARRAY("inputNames", 32, 32, struct_string_32, NULL),
YAML_UNSIGNED( "potsWarnEnabled", 8 ),
YAML_ARRAY("potsWarnPosition", 8, 9, struct_signed_8, NULL),
YAML_ARRAY("telemetrySensors", 112, 60, struct_TelemetrySensor, NULL),
YAML_ARRAY("screenData", 6800, 5, struct_CustomScreenData, NULL),
YAML_STRUCT("topbarData", 2400, struct_Topbar__PersistentData, NULL),
YAML_UNSIGNED( "view", 8 ),
YAML_STRING("modelRegistrationID", 8),
YAML_END
};
#define MAX_RADIODATA_MODELDATA_STR_LEN 24
static const struct YamlNode __RadioData_root_node = YAML_ROOT( struct_RadioData );
const YamlNode* get_radiodata_nodes()
{
return &__RadioData_root_node;
}
static const struct YamlNode __ModelData_root_node = YAML_ROOT( struct_ModelData );
const YamlNode* get_modeldata_nodes()
{
return &__ModelData_root_node;
}

View file

@ -0,0 +1,37 @@
#ifndef _YAML_DEFS_H_
#define _YAML_DEFS_H_
#if defined(YAML_GENERATOR)
/* private definitions */
#define _yaml_note(label) #label
#define _yaml_attribute(attr) __attribute__((annotate(attr)))
/* public definitions */
#define ENUM(label) _yaml_attribute("enum:" _yaml_note(label))
#define SKIP _yaml_attribute("skip:true")
#define USE_IDX _yaml_attribute("idx:true")
#define FUNC(name) _yaml_attribute("func:" _yaml_note(name))
#define NAME(label) _yaml_attribute("name:" _yaml_note(label))
#define CUST(read,write) \
_yaml_attribute("read:" _yaml_note(read)) \
_yaml_attribute("write:" _yaml_note(write))
#define ARRAY(elmt_size,elmt_type,fcn) \
_yaml_attribute("array:" _yaml_note(elmt_size) "|" \
_yaml_note(elmt_type) "|" _yaml_note(fcn))
#else
#define ENUM(label)
#define SKIP
#define USE_IDX
#define FUNC(name)
#define NAME(label)
#define CUST(read,write)
#define ARRAY(elmt_size,elmt_type,fcn)
#endif
#endif

View file

@ -0,0 +1,136 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "yaml_modelslist.h"
#include "yaml_parser.h"
#include "storage/modelslist.h"
using std::list;
struct modelslist_iter
{
enum Level {
Root=0,
Category=1,
Model=2
};
ModelsList* root;
uint8_t level;
char current_attr[16]; // set after find_node()
};
static modelslist_iter __modelslist_iter_inst;
void* get_modelslist_iter()
{
__modelslist_iter_inst.root = &modelslist;
__modelslist_iter_inst.level = 0;
return &__modelslist_iter_inst;
}
static bool to_parent(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Root) {
return false;
}
mi->level--;
return true;
}
static bool to_child(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Model) {
return false;
}
mi->level++;
return true;
}
static bool to_next_elmt(void* ctx)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (mi->level == modelslist_iter::Root) {
return false;
}
return true;
}
static bool find_node(void* ctx, char* buf, uint8_t len)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
if (len > sizeof(modelslist_iter::current_attr)-1)
len = sizeof(modelslist_iter::current_attr)-1;
memcpy(mi->current_attr, buf, len);
mi->current_attr[len] = '\0';
return true;
}
static void set_attr(void* ctx, char* buf, uint8_t len)
{
modelslist_iter* mi = (modelslist_iter*)ctx;
list<ModelsCategory *>& cats = mi->root->getCategories();
switch(mi->level) {
case modelslist_iter::Category: {
ModelsCategory* cat = new ModelsCategory(buf,len);
cats.push_back(cat);
} break;
case modelslist_iter::Model:
if (!strcmp(mi->current_attr,"filename")) {
if (!cats.empty()) {
ModelCell* model = new ModelCell(buf, len);
cats.back()->push_back(model);
mi->root->incModelsCount();
}
}
else if (!strcmp(mi->current_attr,"name")) {
if (!cats.empty()) {
ModelsCategory* cat = cats.back();
if (!cat->empty()) {
ModelCell* model = cat->back();
model->setModelName(buf,len);
}
}
}
break;
}
}
static const YamlParserCalls modelslistCalls = {
to_parent,
to_child,
to_next_elmt,
find_node,
set_attr
};
const YamlParserCalls* get_modelslist_parser_calls()
{
return &modelslistCalls;
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _YAML_MODELSLIST_H_
#define _YAML_MODELSLIST_H_
struct YamlParserCalls;
void* get_modelslist_iter();
const YamlParserCalls* get_modelslist_parser_calls();
#endif

View file

@ -0,0 +1,174 @@
#ifndef _node_h_
#define _node_h_
#include <stdint.h>
#include <stddef.h>
#include "yaml_parser.h"
#define NODE_STACK_DEPTH 12
enum YamlDataType {
YDT_NONE=0,
YDT_IDX,
YDT_SIGNED,
YDT_UNSIGNED,
YDT_STRING,
YDT_ARRAY,
YDT_ENUM,
YDT_UNION,
YDT_PADDING
};
struct YamlIdStr
{
int id;
const char* str;
};
// return false if error
typedef bool (*yaml_writer_func)(void* opaque, const char* str, size_t len);
struct YamlNode
{
typedef bool (*is_active_func)(uint8_t* data, uint32_t bitoffs);
typedef uint32_t (*cust_to_uint_func)(const YamlNode* node, const char* val, uint8_t val_len);
typedef bool (*uint_to_cust_func)(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque);
typedef uint8_t (*select_member_func)(uint8_t* data, uint32_t bitoffs);
typedef uint32_t (*cust_idx_read_func)(const char* val, uint8_t val_len);
typedef bool (*cust_idx_write_func)(uint32_t idx, yaml_writer_func wf, void* opaque);
uint8_t type;
uint32_t size; // bits
uint8_t tag_len;
const char* tag;
union {
struct {
const YamlNode* child;
union {
struct {
is_active_func is_active;
uint16_t elmts; // maximum number of elements
} _a;
select_member_func select_member;
} u;
} _array;
struct {
const YamlIdStr* choices;
} _enum;
struct {
cust_to_uint_func cust_to_uint;
uint_to_cust_func uint_to_cust;
} _cust;
struct {
cust_idx_read_func read;
cust_idx_write_func write;
} _cust_idx;
} u;
};
#if !defined(_MSC_VER)
#define YAML_TAG(str) \
.tag_len=(sizeof(str)-1), .tag=(str)
#define YAML_IDX \
{ .type=YDT_IDX, .size=0, YAML_TAG("idx") }
#define YAML_IDX_CUST(tag, f_read, f_write) \
{ .type=YDT_IDX, .size=0, YAML_TAG(tag), .u={._cust_idx={.read=(f_read), .write=(f_write) }} }
#define YAML_SIGNED(tag, bits) \
{ .type=YDT_SIGNED, .size=(bits), YAML_TAG(tag) }
#define YAML_UNSIGNED(tag, bits) \
{ .type=YDT_UNSIGNED, .size=(bits), YAML_TAG(tag) }
#define YAML_SIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \
{ .type=YDT_SIGNED, .size=(bits), YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} }
#define YAML_UNSIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \
{ .type=YDT_UNSIGNED, .size=(bits), YAML_TAG(tag), .u={._cust={ .cust_to_uint=f_cust_to_uint, .uint_to_cust=f_uint_to_cust }} }
#define YAML_STRING(tag, max_len) \
{ .type=YDT_STRING, .size=((max_len)<<3), YAML_TAG(tag) }
#define YAML_STRUCT(tag, bits, nodes, f_is_active) \
{ .type=YDT_ARRAY, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={ ._a={.is_active=(f_is_active), .elmts=1 }}}} }
#define YAML_ARRAY(tag, bits, max_elmts, nodes, f_is_active) \
{ .type=YDT_ARRAY, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={ ._a={.is_active=(f_is_active), .elmts=(max_elmts) }}}} }
#define YAML_ENUM(tag, bits, id_strs) \
{ .type=YDT_ENUM, .size=(bits), YAML_TAG(tag), .u={._enum={ .choices=(id_strs) }} }
#define YAML_UNION(tag, bits, nodes, f_sel_m) \
{ .type=YDT_UNION, .size=(bits), YAML_TAG(tag), .u={._array={ .child=(nodes), .u={.select_member=(f_sel_m) }}} }
#define YAML_PADDING(bits) \
{ .type=YDT_PADDING, .size=(bits) }
#define YAML_END \
{ .type=YDT_NONE }
#define YAML_ROOT(nodes) \
{ .type=YDT_ARRAY, .size=0, .tag_len=0, .tag=NULL, \
.u={ \
._array={ .child=(nodes), \
.u={._a={.is_active=NULL, .elmts=1 }} \
}} \
}
#else // MSVC++ compat
#define YAML_TAG(str) \
(sizeof(str)-1), (str)
#define YAML_IDX \
{ YDT_IDX , 0, YAML_TAG("idx") }
#define YAML_SIGNED(tag, bits) \
{ YDT_SIGNED, (bits), YAML_TAG(tag) }
#define YAML_UNSIGNED(tag, bits) \
{ YDT_UNSIGNED, (bits), YAML_TAG(tag) }
#define YAML_SIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \
{ YDT_SIGNED, (bits), YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0 }}}} }
#define YAML_UNSIGNED_CUST(tag, bits, f_cust_to_uint, f_uint_to_cust) \
{ YDT_UNSIGNED, (bits), YAML_TAG(tag), {{ (const YamlNode*)f_cust_to_uint, {{ (YamlNode::is_active_func)f_uint_to_cust, 0}}}} }
#define YAML_STRING(tag, max_len) \
{ YDT_STRING, ((max_len)<<3), YAML_TAG(tag) }
#define YAML_STRUCT(tag, bits, nodes, f_is_active) \
{ YDT_ARRAY, (bits), YAML_TAG(tag), {{ (nodes), {{ (f_is_active), 1 }}}} }
#define YAML_ARRAY(tag, bits, max_elmts, nodes, f_is_active) \
{ YDT_ARRAY, (bits), YAML_TAG(tag), {{ (nodes), {{ (f_is_active), (max_elmts) }}}} }
#define YAML_ENUM(tag, bits, id_strs) \
{ YDT_ENUM, (bits), YAML_TAG(tag), {{ (const YamlNode*)(id_strs) }} }
#define YAML_UNION(tag, bits, nodes, f_sel_m) \
{ YDT_UNION, (bits), YAML_TAG(tag), {{ (nodes), {{ (YamlNode::is_active_func)(f_sel_m), 0 }}}} }
#define YAML_PADDING(bits) \
{ YDT_PADDING, (bits) }
#define YAML_END \
{ YDT_NONE }
#define YAML_ROOT(nodes) \
{ YDT_ARRAY, 0, 0, NULL, {{ (nodes), {{ NULL, 1 }}}} }
#endif
#endif

View file

@ -0,0 +1,256 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "yaml_parser.h"
#include "debug.h"
YamlParser::YamlParser()
{
}
void YamlParser::init(const YamlParserCalls* parser_calls, void* parser_ctx)
{
indent = 0;
level = 0;
memset(indents, 0, sizeof(indents));
calls = parser_calls;
ctx = parser_ctx;
reset();
}
void YamlParser::reset()
{
state = ps_Indent;
indents[level] = indent;
indent = scratch_len = 0;
node_found = false;
}
bool YamlParser::toChild()
{
bool ret = calls->to_child(ctx);
if (ret) level++;
return ret;
}
bool YamlParser::toParent()
{
if (!level)
return false;
bool ret = calls->to_parent(ctx);
if (ret) level--;
return ret;
}
uint8_t YamlParser::getLastIndent()
{
return indents[level];
}
YamlParser::YamlResult
YamlParser::parse(const char* buffer, unsigned int size)
{
#define CONCAT_STR(s,s_len,c) \
{ \
if(s_len < MAX_STR) \
s[s_len++] = c; \
else { \
TRACE("STRING_OVERFLOW"); \
return STRING_OVERFLOW; \
} \
}
const char* c = buffer;
const char* end = c + size;
while(c < end) {
switch(state) {
case ps_Indent:
if (*c == '-') {
state = ps_Dash;
++indent;
break;
}
// trap
case ps_Dash:
if (*c == ' ') { // skip space(s), should be only one??
++indent;
break;
}
if (indent < getLastIndent()) {
// go up as many levels as necessary
do {
if (!toParent()) {
TRACE("STOP (no parent)!\n");
return DONE_PARSING;
}
} while (indent < getLastIndent());
if (state == ps_Dash) {
if (!calls->to_next_elmt(ctx)) {
return DONE_PARSING;
}
}
}
// go down one level
else if (indent > getLastIndent()) {
if (!toChild()) {
TRACE("STOP (stack full)!\n");
return DONE_PARSING; // ERROR
}
}
// same level, next element
else if (state == ps_Dash) {
if (!calls->to_next_elmt(ctx)) {
return DONE_PARSING;
}
}
state = ps_Attr;
CONCAT_STR(scratch_buf, scratch_len, *c);
break;
case ps_Attr:
if (*c == ' ') {// assumes nothing else comes after spaces start
node_found = calls->find_node(ctx, scratch_buf, scratch_len);
if (!node_found) {
TRACE("YAML_PARSER: Could not find node '%.*s' (1)\n",
scratch_len, scratch_buf);
}
state = ps_AttrSP;
break;
}
if (*c != ':')
CONCAT_STR(scratch_buf, scratch_len, *c);
// trap
case ps_AttrSP:
if (*c == '\r' || *c == '\n') {
if (state == ps_Attr) {
node_found = calls->find_node(ctx, scratch_buf, scratch_len);
if (!node_found) {
TRACE("YAML_PARSER: Could not find node '%.*s' (2)\n",
scratch_len, scratch_buf);
}
}
state = ps_CRLF;
continue;
}
if (*c == ':') {
if (state == ps_Attr) {
node_found = calls->find_node(ctx, scratch_buf, scratch_len);
if (!node_found) {
TRACE("YAML_PARSER: Could not find node '%.*s' (3)\n",
scratch_len, scratch_buf);
}
}
state = ps_Sep;
break;
}
break;
case ps_Sep:
if (*c == ' ')
break;
if (*c == '\r' || *c == '\n'){
state = ps_CRLF;
continue;
}
state = ps_Val;
scratch_len = 0;
if (*c == '\"') {
state = ps_ValQuo;
break;
}
CONCAT_STR(scratch_buf, scratch_len, *c);
break;
case ps_ValQuo:
if (*c == '\"') {
state = ps_Val;
break;
}
if (*c == '\\') {
state = ps_ValEsc1;
break;
}
CONCAT_STR(scratch_buf, scratch_len, *c);
break;
case ps_ValEsc1:
if (*c == 'x') {
state = ps_ValEsc2;
break;
}
//TODO: more escapes needed???
TRACE("unknown escape char '%c'",*c);
return DONE_PARSING;
case ps_ValEsc2:
if(scratch_len >= MAX_STR) {
TRACE("STRING_OVERFLOW");
return STRING_OVERFLOW;
}
else if (*c >= '0' && *c <= '9') {
scratch_buf[scratch_len] = (*c - '0') << 4;
state = ps_ValEsc3;
break;
}
else if (*c >= 'A' && *c <= 'F') {
scratch_buf[scratch_len] = (*c - 'A' + 10) << 4;
state = ps_ValEsc3;
break;
}
TRACE("wrong hex digit '%c'",*c);
return DONE_PARSING;
case ps_ValEsc3:
if (*c >= '0' && *c <= '9') {
scratch_buf[scratch_len++] |= (*c - '0');
state = ps_ValQuo;
break;
}
else if (*c >= 'A' && *c <= 'F') {
scratch_buf[scratch_len++] |= (*c - 'A' + 10);
state = ps_ValQuo;
break;
}
TRACE("wrong hex digit '%c'",*c);
return DONE_PARSING;
case ps_Val:
if (*c == ' ' || *c == '\r' || *c == '\n') {
// set attribute
if (node_found) {
calls->set_attr(ctx, scratch_buf, scratch_len);
}
state = ps_CRLF;
continue;
}
if (*c == '\"') {
state = ps_ValQuo;
break;
}
CONCAT_STR(scratch_buf, scratch_len, *c);
break;
case ps_CRLF:
if (*c == '\n') {
// reset state at EOL
reset();
}
break;
}
c++;
} // for each char
return CONTINUE_PARSING;
}

View file

@ -0,0 +1,79 @@
#ifndef _yaml_parser_h_
#define _yaml_parser_h_
#include <stdint.h>
#define MAX_STR 40
#define MAX_DEPTH 16 // 12 real + 4 virtual
struct YamlParserCalls
{
bool (*to_parent) (void* ctx);
bool (*to_child) (void* ctx);
bool (*to_next_elmt) (void* ctx);
bool (*find_node) (void* ctx, char* buf, uint8_t len);
void (*set_attr) (void* ctx, char* buf, uint8_t len);
};
class YamlParser
{
enum ParserState {
ps_Indent=0,
ps_Dash,
ps_Attr,
ps_AttrSP,
ps_Sep,
ps_Val,
ps_ValQuo,
ps_ValEsc1,
ps_ValEsc2,
ps_ValEsc3,
ps_CRLF
};
// last indents for each level
uint8_t indents[MAX_DEPTH];
// current indent
uint8_t indent;
// current level
uint8_t level;
// parser state
uint8_t state;
// scratch buffer w/ 16 bytes
// used for attribute and values
char scratch_buf[MAX_STR];
uint8_t scratch_len;
bool node_found;
// tree iterator state
const YamlParserCalls* calls;
void* ctx;
// Reset parser state for next line
void reset();
bool toChild();
bool toParent();
uint8_t getLastIndent();
public:
enum YamlResult {
DONE_PARSING,
CONTINUE_PARSING,
STRING_OVERFLOW
};
YamlParser();
void init(const YamlParserCalls* parser_calls, void* parser_ctx);
YamlResult parse(const char* buffer, unsigned int size);
};
#endif

View file

@ -0,0 +1,620 @@
#include "debug.h"
#include "yaml_node.h"
#include "yaml_bits.h"
#include "yaml_tree_walker.h"
#include "yaml_parser.h"
#include <string.h>
#define MIN(a,b) (a < b ? a : b)
static void copy_string(char* dst, const char* src, uint8_t len)
{
memcpy(dst,src,len);
dst[len] = '\0';
}
uint32_t yaml_parse_enum(const struct YamlIdStr* choices, const char* val, uint8_t val_len)
{
while (choices->str) {
// we have a match!
if (!strncmp(val, choices->str, val_len))
break;
choices++;
}
return choices->id;
}
static void yaml_set_attr(uint8_t* ptr, uint32_t bit_ofs, const YamlNode* node,
const char* val, uint8_t val_len)
{
uint32_t i = 0;
//TRACE("set(%s, %.*s, bit-ofs=%u, bits=%u)\n",
// node->tag, val_len, val, bit_ofs, node->size);
ptr += bit_ofs >> 3UL;
bit_ofs &= 0x07;
if (node->type == YDT_STRING) {
//assert(!bit_ofs);
copy_string((char*)ptr, val, MIN(val_len, node->size - 1));
return;
}
switch(node->type) {
case YDT_SIGNED:
i = node->u._cust.cust_to_uint ? node->u._cust.cust_to_uint(node, val, val_len)
: (uint32_t)yaml_str2int(val, val_len);
break;
case YDT_UNSIGNED:
i = node->u._cust.cust_to_uint ? node->u._cust.cust_to_uint(node, val, val_len)
: yaml_str2uint(val, val_len);
break;
case YDT_ENUM:
i = yaml_parse_enum(node->u._enum.choices, val, val_len);
break;
default:
break;
}
yaml_put_bits(ptr, i, bit_ofs, node->size);
}
const char* yaml_output_enum(int32_t i, const struct YamlIdStr* choices)
{
//TRACE("<choice = %d>", i);
while(choices->str) {
if (i == choices->id)
break;
choices++;
}
return choices->str;
}
static const char hex_digits[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
static bool yaml_output_string(const char* str, uint32_t max_len,
yaml_writer_func wf, void* opaque)
{
if (!wf(opaque, "\"", 1))
return false;
while(*str && max_len > 0) {
if (*str >= 0x20 && *str <= 0x7E) {
if (!wf(opaque, str++, 1)) return false;
max_len--;
}
else {
if (!wf(opaque, "\\x", 2)) return false;
if (!wf(opaque, &(hex_digits[((uint8_t)*str) >> 4]), 1)) return false;
if (!wf(opaque, &(hex_digits[((uint8_t)*str) & 0x0F]), 1)) return false;
str++; max_len--;
}
}
if (!wf(opaque, "\"", 1))
return false;
return true;
}
static bool yaml_output_attr(uint8_t* ptr, uint32_t bit_ofs, const YamlNode* node,
yaml_writer_func wf, void* opaque)
{
if (node->type == YDT_NONE)
return false;
if (node->type == YDT_PADDING)
return true;
// output tag
if (!wf(opaque, node->tag, node->tag_len))
return false;
if (!wf(opaque, ": ", 2))
return false;
if (ptr) {
ptr += bit_ofs >> 3UL;
bit_ofs &= 0x07;
const char* p_out = NULL;
if (node->type == YDT_STRING) {
//assert(!bit_ofs);
if (!yaml_output_string((const char*)ptr, (node->size)>>3UL, wf, opaque))
return false;
}
else {
unsigned int i = yaml_get_bits(ptr, bit_ofs, node->size);
if ((node->type == YDT_SIGNED || node->type == YDT_UNSIGNED)
&& node->u._cust.uint_to_cust) {
return node->u._cust.uint_to_cust(node, i, wf, opaque)
&& wf(opaque, "\r\n", 2);
}
else {
switch(node->type) {
case YDT_SIGNED:
p_out = yaml_signed2str((int)yaml_to_signed(i, node->size));
break;
case YDT_UNSIGNED:
p_out = yaml_unsigned2str(i);
break;
case YDT_ENUM:
p_out = yaml_output_enum(i, node->u._enum.choices);
break;
case YDT_ARRAY:
case YDT_UNION:
default:
break;
}
}
}
if (p_out && !wf(opaque, p_out, strlen(p_out)))
return false;
}
return wf(opaque, "\r\n", 2);
}
YamlTreeWalker::YamlTreeWalker()
: stack_level(NODE_STACK_DEPTH),
virt_level(0),
anon_union(0)
{
memset(stack,0,sizeof(stack));
}
void YamlTreeWalker::reset(const YamlNode* node, uint8_t* data)
{
this->data = data;
stack_level = NODE_STACK_DEPTH;
virt_level = 0;
push();
setNode(node);
rewind();
}
bool YamlTreeWalker::push()
{
if (full())
return false;
stack_level--;
memset(&(stack[stack_level]), 0, sizeof(State));
return true;
}
bool YamlTreeWalker::pop()
{
if (empty())
return false;
memset(&(stack[stack_level]), 0, sizeof(State));
stack_level++;
return true;
}
// Rewind to the current node's first attribute
// (and reset the bit offset)
void YamlTreeWalker::rewind()
{
if (getNode()->type == YDT_ARRAY
|| getNode()->type == YDT_UNION) {
setAttrIdx(0);
setAttrOfs(getLevelOfs());
}
}
// Increment the cursor until a match is found or the end of
// the current collection (node of type YDT_NONE) is reached.
//
// return true if a match has been found.
bool YamlTreeWalker::findNode(const char* tag, uint8_t tag_len)
{
if (virt_level)
return false;
rewind();
const struct YamlNode* attr = getAttr();
while(attr && attr->type != YDT_NONE) {
if ((tag_len == attr->tag_len)
&& !strncmp(tag, attr->tag, tag_len)) {
return true; // attribute found!
}
toNextAttr();
attr = getAttr();
}
return false;
}
// Get the current bit offset
unsigned int YamlTreeWalker::getBitOffset()
{
return stack[stack_level].getOfs();
}
bool YamlTreeWalker::toParent()
{
if(virt_level) {
virt_level--;
return true;
}
if (!pop())
return false;
return !empty();
}
bool YamlTreeWalker::toChild()
{
const struct YamlNode* attr = getAttr();
if (!attr
|| (attr->type != YDT_ARRAY
&& attr->type != YDT_UNION)) {
virt_level++;
return true;
}
if (!push()) {
virt_level++;
return false;
}
setNode(attr);
setAttrOfs(getLevelOfs());
attr = getAttr();
if ((attr->type == YDT_UNION) && (attr->tag_len == 0)) {
toChild();
anon_union++;
}
return true;
}
bool YamlTreeWalker::toNextElmt()
{
const struct YamlNode* node = getNode();
if (!virt_level && (node->type == YDT_ARRAY
|| node->type == YDT_UNION)) {
if (node->type == YDT_UNION) {
return false;
}
if (getElmts() >= node->u._array.u._a.elmts - 1)
return false;
incElmts();
rewind();
}
return true;
}
bool YamlTreeWalker::isElmtEmpty(uint8_t* data)
{
if (virt_level)
return true;
if (!data)
return false;
const struct YamlNode* node = getNode();
uint32_t bit_ofs = 0;
if (node->type == YDT_ARRAY) {
bit_ofs = ((uint32_t)getElmts())
* getNode()->size
+ getLevelOfs();
// assume structs aligned on 8bit boundaries
if (node->u._array.u._a.is_active)
return !node->u._array.u._a.is_active(data, bit_ofs);
return yaml_is_zero(data, bit_ofs, node->size);
}
else if ((node->type == YDT_UNION) && hasParent()) {
bit_ofs = getLevelOfs();
TRACE("<not empty>");
return false;//node->u._array.u.select_member; //TODO!
// // assume structs aligned on 8bit boundaries
// && !node->_array.is_active(data + (bit_ofs >> 3));
}
return false;
}
void YamlTreeWalker::toNextAttr()
{
const struct YamlNode* node = getNode();
const struct YamlNode* attr = NULL;
if (node->type != YDT_UNION) {
attr = getAttr();
uint32_t attr_bit_ofs = getAttrOfs();
if (attr->type == YDT_ARRAY)
attr_bit_ofs += ((uint32_t)attr->u._array.u._a.elmts * attr->size);
else
attr_bit_ofs += attr->size;
setAttrOfs(attr_bit_ofs);
}
incAttr();
// anonymous union handling
attr = getAttr();
if ((attr->type == YDT_UNION) && (attr->tag_len == 0)) {
toChild();
anon_union++;
}
else if ((attr->type == YDT_NONE)
&& (getNode()->type == YDT_UNION)
&& anon_union) {
anon_union--;
toParent();
toNextAttr();
}
}
void YamlTreeWalker::setAttrValue(char* buf, uint8_t len)
{
if (!buf || !len)
return;
const YamlNode* attr = getAttr();
if (attr->type == YDT_IDX) {
uint32_t i = 0;
if (attr->u._cust_idx.read)
i = attr->u._cust_idx.read(buf, len);
else
i = yaml_str2uint(buf, len);
while ((i > getElmts()) && toNextElmt());
}
else {
yaml_set_attr(data, getBitOffset(), attr, buf, len);
//walker.dump_stack();
}
}
bool YamlTreeWalker::generate(yaml_writer_func wf, void* opaque)
{
bool new_elmt = false;
while (true) {
const struct YamlNode* attr = getAttr();
if (attr->type == YDT_PADDING) {
toNextAttr();
continue;
}
// end of this level, go up or die
if (attr->type == YDT_NONE) {
const struct YamlNode* node = getNode();
if (node->type != YDT_ARRAY && node->type != YDT_UNION)
return false; // Error in the structure (probably)
// if parent is a union, no need to output the other elements...
const YamlNode* parent = getParent();
if (parent && (parent->type == YDT_UNION)) {
if (!toParent())
return false;
}
else {
// walk to next non-empty element
while (toNextElmt()) {
if (!isElmtEmpty(data)) {
new_elmt = true;
break;
}
}
if (new_elmt)
continue;
}
// no next element, go up
if (!toParent())
return true;
toNextAttr();
continue;
}
else if (attr->type == YDT_ARRAY || attr->type == YDT_UNION) {
if (!toChild())
return false; // TODO: error handling???
const struct YamlNode* node = getNode();
if (node->type == YDT_UNION && node->u._array.u.select_member) {
// output union tag, select member and go up one level
// output union tag
for(int i=2; i < getLevel(); i++)
if (!wf(opaque, " ", 3))
return false;
if (!yaml_output_attr(NULL, 0, node, wf, opaque))
return false; // TODO: error handling???
// grab attr idx...
uint8_t idx = node->u._array.u.select_member(data, getBitOffset());
//TRACE("<idx = %d>", idx);
setAttrIdx(idx);
attr = getAttr();
for(int i=1; i < getLevel(); i++)
if (!wf(opaque, " ", 3))
return false;
if (!yaml_output_attr(data, getBitOffset(), attr, wf, opaque))
return false; // TODO: error handling???
if (attr->type != YDT_ARRAY
&& attr->type != YDT_UNION) {
if (!toParent())
return false;
toNextAttr();
}
else {
if (!toChild() && !toParent())
return false;
}
continue;
}
// walk to next non-empty element
do {
if (!isElmtEmpty(data)) {
new_elmt = true;
break;
}
new_elmt = false;
} while (toNextElmt());
if (new_elmt) {
// non-empty element present in a new structure/array
// let's output the attribute
for(int i=2; i < getLevel(); i++)
if (!wf(opaque, " ", 3))
return false;
if (!yaml_output_attr(NULL, 0, getNode(), wf, opaque))
return false; // TODO: error handling???
continue;
}
// no next element, go up
if (!toParent())
return true;
toNextAttr();
continue;
}
if (new_elmt) {
for(int i=2; i < getLevel(); i++)
if (!wf(opaque, " ", 3))
return false;
if (!wf(opaque, " - ", 3))
return false;
new_elmt = false;
}
else {
for(int i=1; i < getLevel(); i++)
if (!wf(opaque, " ", 3))
return false;
}
if (attr->type == YDT_IDX) {
if (!wf(opaque, attr->tag, attr->tag_len))
return false;
if (!wf(opaque, ": ", 2))
return false;
if (attr->u._cust_idx.write) {
if (!attr->u._cust_idx.write(getElmts(),wf,opaque))
return false;
}
else {
char* idx = yaml_unsigned2str(getElmts());
if (!wf(opaque, idx, strlen(idx)))
return false;
}
if (!wf(opaque, "\r\n", 2))
return false;
}
else if (!yaml_output_attr(data, getBitOffset(), attr, wf, opaque))
return false; // TODO: error handling???
toNextAttr();
}
return true;
}
void YamlTreeWalker::dump_stack()
{
for (int i=0; i<NODE_STACK_DEPTH; i++) {
TRACE(" [%p|%u|%i|%i]",
stack[i].node,stack[i].bit_ofs,
stack[i].attr_idx,stack[i].elmts);
}
TRACE("\n");
}
static bool to_parent(void* ctx)
{
return ((YamlTreeWalker*)ctx)->toParent();
}
static bool to_child(void* ctx)
{
return ((YamlTreeWalker*)ctx)->toChild();
}
static bool to_next_elmt(void* ctx)
{
return ((YamlTreeWalker*)ctx)->toNextElmt();
}
static bool find_node(void* ctx, char* buf, uint8_t len)
{
return ((YamlTreeWalker*)ctx)->findNode(buf,len);
}
static void set_attr(void* ctx, char* buf, uint8_t len)
{
return ((YamlTreeWalker*)ctx)->setAttrValue(buf,len);
}
const YamlParserCalls YamlTreeWalkerCalls = {
to_parent,
to_child,
to_next_elmt,
find_node,
set_attr
};
const YamlParserCalls* YamlTreeWalker::get_parser_calls()
{
return &YamlTreeWalkerCalls;
}

View file

@ -0,0 +1,122 @@
#ifndef _YAML_TREE_WALKER_H_
#define _YAML_TREE_WALKER_H_
#include <stdint.h>
#include "yaml_node.h"
struct YamlParserCalls;
class YamlTreeWalker
{
struct State {
const YamlNode* node;
uint32_t bit_ofs;
int8_t attr_idx;
uint16_t elmts;
inline uint32_t getOfs() {
return bit_ofs + node->size * elmts;
}
};
State stack[NODE_STACK_DEPTH];
uint8_t stack_level;
uint8_t virt_level;
uint8_t anon_union;
uint8_t* data;
uint32_t getAttrOfs() { return stack[stack_level].bit_ofs; }
uint32_t getLevelOfs() {
if (hasParent()) {
return stack[stack_level + 1].getOfs();
}
return 0;
}
const YamlNode* getParent() {
if (hasParent())
return stack[stack_level + 1].node;
return nullptr;
}
void setNode(const YamlNode* node) { stack[stack_level].node = node; }
void setAttrIdx(uint8_t idx) { stack[stack_level].attr_idx = idx; }
void setAttrOfs(unsigned int ofs) { stack[stack_level].bit_ofs = ofs; }
void incAttr() { stack[stack_level].attr_idx++; }
void incElmts() { stack[stack_level].elmts++; }
bool empty() { return stack_level == NODE_STACK_DEPTH; }
bool full() { return stack_level == 0; }
bool hasParent() { return stack_level < NODE_STACK_DEPTH -1; }
// return true on success
bool push();
bool pop();
// Rewind to the current node's first attribute
// (and reset the bit offset)
void rewind();
public:
YamlTreeWalker();
void reset(const YamlNode* node, uint8_t* data);
int getLevel() {
return NODE_STACK_DEPTH - stack_level
+ virt_level - anon_union;
}
const YamlNode* getNode() {
return stack[stack_level].node;
}
const YamlNode* getAttr() {
int8_t idx = stack[stack_level].attr_idx;
if (idx >= 0)
return &(stack[stack_level].node->u._array.child[idx]);
return NULL;
}
uint16_t getElmts() {
return stack[stack_level].elmts;
}
// Increment the cursor until a match is found or the end of
// the current collection (node of type YDT_NONE) is reached.
//
// return true if a match has been found.
bool findNode(const char* tag, uint8_t tag_len);
// Get the current bit offset
unsigned int getBitOffset();
bool toParent();
bool toChild();
bool toNextElmt();
void toNextAttr();
bool isElmtEmpty(uint8_t* data);
void setAttrValue(char* buf, uint8_t len);
bool generate(yaml_writer_func wf, void* opaque);
void dump_stack();
static const YamlParserCalls* get_parser_calls();
};
// utils
uint32_t yaml_parse_enum(const struct YamlIdStr* choices, const char* val, uint8_t val_len);
const char* yaml_output_enum(int32_t i, const struct YamlIdStr* choices);
#endif

View file

@ -8,7 +8,8 @@ set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")
set(CPU_TYPE STM32F4)
set(HSE_VALUE 12000000)
set(SDCARD YES)
set(EEPROM SDCARD)
set(STORAGE SDCARD)
set(STORAGE_FORMAT BIN)
set(HAPTIC YES)
set(GUI_DIR colorlcd)
set(NAVIGATION_TYPE horus)
@ -24,6 +25,11 @@ set(RAMBACKUP YES)
set(PPM_LIMITS_SYMETRICAL YES)
set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)")
option(YAML_STORAGE "Enable YAML storage" NO)
if(YAML_STORAGE)
set(STORAGE_FORMAT YAML)
endif()
# for size report script
set(CPU_TYPE_FULL STM32F429xI)
set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM2=8192")

View file

@ -124,7 +124,7 @@ uint32_t sdMounted();
#endif
#if defined(DISK_CACHE)
#include "diskio.h"
#include "FatFs/diskio.h"
DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count);
DRESULT __disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count);
#else

View file

@ -124,11 +124,20 @@ bool redirectToSettingsDirectory(const std::string & path)
*/
if (!simuSettingsDirectory.empty()) {
#if defined(COLORLCD)
if (path == RADIO_MODELSLIST_PATH || path == RADIO_SETTINGS_PATH) {
if (path == RADIO_MODELSLIST_PATH || path == RADIO_SETTINGS_PATH
#if defined(SDCARD_YAML)
|| path == RADIO_MODELSLIST_YAML_PATH || path == RADIO_SETTINGS_YAML_PATH
#endif
) {
return true;
}
#endif
if (startsWith(path, "/MODELS") && endsWith(path, MODELS_EXT)) {
if (startsWith(path, "/MODELS")
&& (endsWith(path, MODELS_EXT)
#if defined(SDCARD_YAML)
|| endsWith(path, YAML_EXT)
#endif
)) {
return true;
}
}

View file

@ -3,7 +3,8 @@ set(LUA NO)
set(MCU cortex-m3)
set(SDCARD YES)
set(HAPTIC YES)
set(EEPROM EEPROM_RAW)
set(STORAGE EEPROM)
set(STORAGE_FORMAT RAW)
set(GUI_DIR 128x64)
set(NAVIGATION_TYPE 9x)
set(TARGET_DIR sky9x)

View file

@ -271,7 +271,8 @@ endif()
set(HSE_VALUE 12000000)
set(SDCARD YES)
set(EEPROM EEPROM_RLC)
set(STORAGE EEPROM)
set(STORAGE_FORMAT RLC)
set(TARGET_DIR taranis)
set(PPM_LIMITS_SYMETRICAL YES)

View file

@ -223,7 +223,7 @@ void processTelemetryFrame(uint8_t module, uint8_t * frame)
}
}
#if defined(ACCESS_LIB)
#if defined(ACCESS_LIB) && !defined(SIMU)
void processAuthenticationFrame(uint8_t module, uint8_t * frame)
{
uint8_t cryptoType = frame[3];

View file

@ -84,7 +84,7 @@ PACK(struct CellValue
void set(uint16_t newValue)
{
if (newValue > 50) {
value = value;
value = newValue;
state = 1;
}
}

@ -1 +1 @@
Subproject commit 79a6921d2386236a44e87554195bf41dc412b445
Subproject commit 1bae467262bbe8232111a6baee7195850cef2531

@ -1 +1 @@
Subproject commit 24ef5848392ac2a6196f97d277ba54ded8965e4c
Subproject commit 385c511755dd9ba5814a9bf46ceb0ce499efd162

26
radio/util/dump_ast.py Normal file
View file

@ -0,0 +1,26 @@
#!/usr/bin/python
# vim: set fileencoding=utf-8
import clang.cindex
import asciitree # must be version 0.2
import sys
def node_children(node):
return list(c for c in node.get_children() if c is not None and c.location is not None and c.location.file is not None and c.location.file.name == sys.argv[1])
def print_node(node):
text = node.spelling or node.displayname
kind = str(node.kind)[str(node.kind).index('.')+1:]
if clang.cindex.CursorKind.FIELD_DECL == node.kind:
size = node.type.get_size()
return '{} {} {}'.format(kind, text, size)
return '{} {}'.format(kind, text)
if len(sys.argv) < 2:
print("Usage: dump_ast.py [header file name] [additional compile args]")
sys.exit()
clang.cindex.Config.set_library_file('/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib')
index = clang.cindex.Index.create()
translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11'] + sys.argv[2:])
print(asciitree.draw_tree(translation_unit.cursor, node_children, print_node))

182
radio/util/dump_ast_yaml.py Normal file
View file

@ -0,0 +1,182 @@
#!/usr/bin/python
# vim: set fileencoding=utf-8
from clang.cindex import *
import asciitree # must be version 0.2
import sys
TOP_NODE_TYPES = [
CursorKind.ENUM_DECL,
CursorKind.STRUCT_DECL ]
CHILD_NODE_TYPES = [
CursorKind.FIELD_DECL,
CursorKind.UNION_DECL,
#CursorKind.STRUCT_DECL,
CursorKind.ENUM_CONSTANT_DECL ]
def filter_node(node):
if node is None:
return False
# # no node or no location
# if node is None or node.location is None or node.location.file is None:
# return False
# # not the main source file
# if node.location.file.name != sys.argv[1]:
# return False
if node.kind in CHILD_NODE_TYPES:
return True
return False
def get_struct_decl(node):
for c in node.get_children():
if c is not None and c.kind == CursorKind.STRUCT_DECL:
return c
return None
def node_children(node):
if node is None:
return []
if isinstance(node,list):
return node
if node.kind == CursorKind.FIELD_DECL:
if node.type.kind == TypeKind.ELABORATED:
return node_children(node.type.get_declaration())
elif node.type.kind == TypeKind.RECORD:
return list(c for c in node.type.get_fields())
elif node.type.kind == TypeKind.CONSTANTARRAY:
et = node.type.element_type
if et.kind == TypeKind.RECORD:
return list(c for c in et.get_fields())
elif node.type.kind == TypeKind.ENUM:
return node_children(node.type.get_declaration())
else:
print("{} {}".format(str(node.type.kind),node.spelling))
return list(c for c in node.get_children() if filter_node(c))
def get_array_size(f):
et = f.type.element_type
ec = f.type.element_count
if et.spelling == 'char':
return 'string({})'.format(ec)
else:
return '{} x {} bytes'.format(ec,et.get_size())
def get_field_size(f):
if f.is_bitfield():
return '{} bits'.format(f.get_bitfield_width())
elif f.type.kind == TypeKind.CONSTANTARRAY:
return get_array_size(f)
return '{} bytes'.format(f.type.get_size())
def print_field_decl(kind, text, f):
ft = ''
is_anon = f.is_anonymous()
if f.type.kind == TypeKind.RECORD:
decl = f.type.get_declaration()
if decl.kind == CursorKind.UNION_DECL:
if is_anon:
ft = 'anonymous union ({})'.format(decl.mangled_name)
else:
ft = 'union {}'.format(f.type.spelling)
elif decl.kind == CursorKind.STRUCT_DECL:
if is_anon:
ft = '{} anonymous struct'.format(f.kind)
else:
ft = 'struct {}'.format(f.type.spelling)
elif f.type.kind == TypeKind.TYPEDEF:
decl = f.type.get_canonical()
ft = decl.spelling
elif get_struct_decl(f) is not None:
ft = 'anon struct'
elif f.type.kind == TypeKind.CONSTANTARRAY:
et = f.type.element_type
ft = et.spelling
else:
ft = f.type.spelling
return '{} {} ({})'.format(ft, text, get_field_size(f))
def print_enum_decl(kind, text, e):
return '{} {} ({})'.format(kind, text, e.enum_value)
def print_union_decl(kind, text, f):
return '{} {} ({})'.format(kind, text, get_field_size(f))
def print_node(node):
if isinstance(node,list):
return 'ROOT'
text = node.spelling or node.displayname
kind = str(node.kind)[str(node.kind).index('.')+1:]
if CursorKind.FIELD_DECL == node.kind:
return print_field_decl(kind, text, node)
if CursorKind.ENUM_CONSTANT_DECL == node.kind:
return print_enum_decl(kind, text, node)
if CursorKind.UNION_DECL == node.kind:
return print_union_decl(kind, text, node)
return '{} {}'.format(kind, text)
def get_top_node(name, node):
for c in node.get_children():
if c.spelling == name:
# struct found
return c
print("get_top_node: '{}' not found!".format(name))
return None
def get_top_nodes(node):
l = list()
for c in node.get_children():
# no node or no location
if c is None or c.location is None or c.location.file is None:
continue
# not the main source file
if c.location.file.name != sys.argv[1]:
continue
if c.kind in TOP_NODE_TYPES:
# struct found
l.append(c)
return l
def print_top_node(name):
s = get_top_node(name, translation_unit.cursor)
if s is None:
return
print(asciitree.draw_tree(s, node_children, print_node))
def print_all():
s = get_top_nodes(translation_unit.cursor)
print(asciitree.draw_tree(s, node_children, print_node))
### Main ###
if len(sys.argv) < 3:
print("Usage: dump_ast_yaml.py [header file name] [top node] [additional compile args]")
sys.exit()
Config.set_library_file('/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib')
index = Index.create()
translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11'] + sys.argv[3:])
print_top_node(sys.argv[2])
#print_top_node('CustomFunctionData')
#print_all()

564
radio/util/generate_yaml.py Normal file
View file

@ -0,0 +1,564 @@
#!/usr/bin/python
import os
import sys
from clang.cindex import *
# debug
import asciitree # must be version 0.2
# output
import jinja2
DEBUG_ATTRS = ['layoutData','topbarData','widgetData']
#USE_FAKE_STRUCT = False
USE_FAKE_STRUCT = True
def node_children(node):
l = list(c for c in node.get_children() if c is not None)
if len(l) > 0:
return l
return []
#decl = node.type.get_declaration()
#return list(c for c in decl.get_children() if c is not None)
def print_node(node):
text = node.spelling or node.displayname
kind = str(node.kind)[str(node.kind).index('.')+1:]
if CursorKind.FIELD_DECL == node.kind:
size = node.type.get_size()
return '{} {} {}'.format(kind, text, size)
return '{} {}'.format(kind, text)
def dump_node(node):
print(asciitree.draw_tree(node, node_children, print_node))
has_errors = False
def print_error(*args):
print("ERROR:",*args,file=sys.stderr)
has_errors = True
def print_debug(*args):
print("DBG:",*args,file=sys.stderr)
def bail_out(*args):
print_error(*args)
sys.exit(-1)
_anon_cnt = 0
def get_next_anon():
global _anon_cnt
label = str(_anon_cnt)
_anon_cnt = _anon_cnt + 1
return label
SIGNED_TYPES = ['bool', 'char', 'short', 'int', 'long' ]
def map_type(type_name):
if 'unsigned' in type_name:
return 'unsigned'
elif ('signed' in type_name) or (type_name in SIGNED_TYPES):
return 'signed'
return type_name
def mangle_type(type_name):
return type_name.replace(':','_')
# Cursor or Type
def get_type(obj):
if isinstance(obj,Cursor):
return obj.type
else:
return obj
def is_string(type):
if type.kind == TypeKind.CONSTANTARRAY:
if type.element_type.spelling == 'char':
return True
return False
class AST_Element:
def __init__(self, name, cursor):
self.name = name
self.cursor = cursor
self.elmts = []
def get_children(self):
return self.cursor.get_children()
def get_elmts(self):
return self.elmts
def append(self,elmt):
if isinstance(elmt, list):
self.elmts.extend(elmt)
else:
self.elmts.append(elmt)
def str(self):
if hasattr(self,'value'):
if hasattr(self,'ann'):
return '{}:\t{} ({})'.format(self.name,self.value,self.ann)
return '{}:\t{}'.format(self.name,self.value)
elif hasattr(self,'type'):
if hasattr(self,'var_type'):
return '{} {}\t{}'.format(self.type, self.var_type, self.name)
else:
return '{}\t{}'.format(self.type, self.name)
return self.name
class FieldAST(AST_Element):
def __init__(self, name, cursor):
super(FieldAST, self).__init__(name, cursor)
self.is_array = False
self.func = 'NULL'
if self.name in DEBUG_ATTRS:
#print("# field name={} type={} canon={} decl={}".format(self.name,cursor.type.spelling,cursor.type.get_canonical().spelling,str(cursor.type.kind)))
#dump_node(cursor)
pass
if isinstance(cursor,Cursor):
t = cursor.type
if cursor.is_bitfield():
self.bits = cursor.get_bitfield_width()
else:
# cursor is a type...
t = cursor
if not hasattr(self,'bits'):
self.bits = t.get_size() * 8
if t.kind == TypeKind.TYPEDEF:
self.type = map_type(t.get_canonical().spelling)
elif t.kind == TypeKind.CONSTANTARRAY:
self.type = t.element_type.spelling
self.is_array = True
self.length = t.element_count
if self.type == 'char':
self.type = 'string'
else:
self.type = map_type(t.spelling)
class StructAST(AST_Element):
type = 'struct'
def __init__(self, name, cursor, alt_name=''):
self.var_name = name
if len(alt_name) > 0:
name = alt_name
if name == '':
name = self.name_prefix() + 'anonymous_' + get_next_anon()
else:
name = self.name_prefix() + name
self.func = 'NULL'
super(StructAST, self).__init__(name, cursor)
def name_prefix(self):
return self.type + '_'
class UnionAST(StructAST):
type = 'union'
class EnumAST(AST_Element):
type = 'enum'
def __init__(self, name, cursor):
self.var_name = name
super(EnumAST, self).__init__('enum_' + name, cursor)
class AST:
name = 'ROOT'
def __init__(self):
self.structs = []
self.enums = []
def has_enum(self,name):
for e in self.enums:
if e.name == name:
return True
return False
def get_enums(self):
return self.enums
def get_structs(self):
return self.structs
def has_struct(self,name):
for s in self.structs:
if s.name == name:
return True
return False
def get_struct(self,name):
for s in self.structs:
if s.name == name:
return s
return None
def get_elmts(self):
return self.enums + self.structs
def append(self, elmt):
if isinstance(elmt, StructAST):
self.structs.append(elmt)
elif isinstance(elmt, EnumAST):
self.enums.append(elmt)
def str(self):
return self.name
def parse_struct(ast, node, alt_name):
st = None
if ast is not RootAST:
ast.var_type = ast.type
ast.type = 'struct'
st = StructAST(node.spelling, node, alt_name)
if (ast is RootAST):
old_st = RootAST.get_struct(st.name)
if old_st is not None:
return old_st
st.use_idx = False
ann = get_annotations(node)
if len(ann) > 0:
#print(ann)
for a in ann:
if a['type'] == 'idx' and a['val'] == 'true':
st.use_idx = True
break
for c in node.get_children():
parse_field(st,c)
if st is not ast:
ast.append(st)
#print_debug("IDX ",st.name, " ", st.use_idx)
return st
def parse_union(ast, node):
st = None
if ast is not RootAST:
ast.var_type = ast.type
ast.type = 'union'
st = UnionAST(node.spelling, node)
if (ast is RootAST):
old_st = RootAST.get_struct(st.name)
if old_st is not None:
return old_st
for c in node.get_children():
parse_field(st,c)
ann = get_annotations(node)
if len(ann) > 0:
for a in ann:
if a['type'] == 'func':
st.func = a['val']
if st is not ast:
ast.append(st)
return st
def get_annotations(node):
l = list()
for c in node.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
ann = c.displayname.split(':')
l.append({'type':ann[0], 'val':ann[1]})
return l
def parse_field_record(f, node):
alt_name = ''
decl = node.type.get_declaration()
if not decl.spelling == '':
alt_name = mangle_type(node.type.spelling)
#print("alt_name = " + alt_name)
st = parse_node(RootAST,decl,alt_name)
if st is not None:
f.var_type = st.name
f.var_name = alt_name
f.type = st.type
def make_fake_array_struct(f, node_type, use_idx):
# if not USE_FAKE_STRUCT:
# f.var_type = node_type.spelling
# # if is_string(get_type(node_type)):
# # f.type = 'array'
# # f.length = get_type(node_type).element_count
# return
field = FieldAST('val', node_type)
#field.is_fake = True
type_name = field.type + '_' + str(field.bits)
struct_name = 'struct_' + type_name
if USE_FAKE_STRUCT and not RootAST.has_struct(struct_name):
#print("# field created " + struct_name)
st = StructAST(type_name, node_type)
st.append(field)
st.used_in_arrays = True
st.use_idx = use_idx
RootAST.append(st)
f.var_name = f.type
f.type = 'array'
f.var_type = struct_name
#f.var_name = field.type
def parse_field_array(f, node):
et = node.type.element_type
if f.type != 'string':
elmt_decl = et.get_declaration()
use_idx = False
ann = get_annotations(node)
if len(ann) > 0:
for a in ann:
if a['type'] == 'idx':
use_idx = True
# let's see first if it's some kind of struct/union/enum
elmt_st = parse_node(RootAST, elmt_decl)
if elmt_st is not None:
f.type = 'array'
f.var_type = elmt_st.name
f.var_name = elmt_st.var_name
# mark array usage for unions
elmt_st.used_in_arrays = True
elif elmt_decl.kind == CursorKind.TYPEDEF_DECL:
# it's some typedef
#print_error("TYPEDEF {} {}".format(f.name, elmt_decl.spelling));
make_fake_array_struct(f, elmt_decl, use_idx)
elif et.kind == TypeKind.CONSTANTARRAY:
# it's an array:
# let's create a fake struct with the element type
#print_error("ARRAY {} {}".format(f.name, elmt_decl.spelling));
make_fake_array_struct(f, et, use_idx)
else:
pass
#print("# unknown array attr: {} {}".format(str(elmt_decl.kind), f.name))
def parse_field(ast,node):
if (not node.is_anonymous()) and (node.kind != CursorKind.FIELD_DECL):
return
f = FieldAST(node.spelling, node)
if node.type.kind in [TypeKind.ELABORATED, TypeKind.RECORD, TypeKind.ENUM]:
parse_field_record(f, node)
elif node.type.kind == TypeKind.CONSTANTARRAY:
parse_field_array(f, node)
ann = get_annotations(node)
if len(ann) > 0:
for a in ann:
if a['type'] == 'enum':
if not hasattr(f,'f_read'):
f.type = 'enum'
enum_name = 'enum_' + a['val']
f.var_type = enum_name
if not RootAST.has_enum(enum_name):
parse_node(RootAST,get_top_node(a['val']))
elif a['type'] == 'func':
f.func = a['val']
elif a['type'] == 'name':
f.name = a['val']
elif a['type'] == 'read':
f.f_read = a['val']
elif a['type'] == 'write':
f.f_write = a['val']
elif a['type'] == 'array':
array_attrs = a['val'].split('|')
elmt_size = int(array_attrs[0])
f.var_type = array_attrs[1]
f.type = 'array'
f.length = int(f.bits / elmt_size)
f.func = array_attrs[2]
elif a['type'] == 'skip':
f.skip = True
if len(f.name) == 0:
print_error("in '{}', field of type '{}' does not have a name".format(ast.name,f.var_type))
ast.append(f)
def parse_enum_field(ast,node):
ann = get_annotations(node)
if len(ann) > 0:
for a in ann:
if a['type'] == 'skip':
return
enum_value = node.spelling
if '_' in enum_value:
enum_value = enum_value[enum_value.index('_')+1:]
st = AST_Element(enum_value, node)
st.value = node.spelling #node.enum_value
ast.append(st)
# debug
if len(ann) > 0:
#print(ann)
st.ann = ann
def parse_enum(ast,node):
st = EnumAST(node.spelling or node.displayname, node)
for c in node.get_children():
parse_enum_field(st,c)
ast.append(st)
return st
def parse_node(ast,node,alt_name=''):
st = None
if node.kind in [CursorKind.STRUCT_DECL,CursorKind.CLASS_DECL]:
st = parse_struct(ast,node,alt_name)
elif node.kind == CursorKind.UNION_DECL:
st = parse_union(ast,node)
elif node.kind == CursorKind.FIELD_DECL:
parse_field(ast,node)
elif node.kind == CursorKind.ENUM_DECL:
st = parse_enum(ast,node)
else:
pass
return st
### main ###
def get_top_node(name):
node = translation_unit.cursor
for c in node.get_children():
if c.spelling == name:
# struct found
return c.get_definition()
bail_out(f"'{name}' not found")
def ast_children(ast_node):
if ast_node is not None:
return ast_node.get_elmts()
return []
def print_ast_node(ast_node):
#if isinstance(ast_node,dict):
# return str(ast_node)
return ast_node.str()
if len(sys.argv) < 2:
bail_out(f"usage: {sys.argv[0]} [header file name] [template] [node name] [additional compile args]")
CLANG_LIB_LOCATIONS = [
'/usr/local/Cellar/llvm/6.0.0/lib/libclang.dylib',
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib',
'/Library/Developer/CommandLineTools/usr/lib/libclang.dylib',
'/usr/lib/x86_64-linux-gnu/libclang-3.8.so.1'
]
# set clang lib file
for lib in CLANG_LIB_LOCATIONS:
if os.path.exists(lib):
Config.set_library_file(lib)
break
# compile source file
index = Index.create()
translation_unit = index.parse(sys.argv[1], ['-x', 'c++', '-std=c++11', '-Wno-deprecated-register'] + sys.argv[4:])
def show_tu_diags(diags, prefix=''):
tu_errors = 0
for diag in diags:
tu_errors = tu_errors + 1
print_error(prefix + str(diag))
show_tu_diags(diag.children, ' ' + prefix)
return tu_errors
tu_errors = show_tu_diags(translation_unit.diagnostics)
if tu_errors > 0:
bail_out("{} error(s) while compiling '{}'".format(tu_errors, sys.argv[1]))
RootAST = AST()
root_nodes_name = ''
top_node_names = sys.argv[3].split(',')
# cycle on top nodes:
for tn in top_node_names:
top_node = get_top_node(tn)
#dump_node(top_node)
parse_node(RootAST, top_node)
if len(root_nodes_name) > 0:
root_nodes_name = root_nodes_name + '_' + tn
else:
root_nodes_name = tn
# Do not generate anything we had some errors
if has_errors:
sys.exit(-1)
#print("Enums:", RootAST.get_enums())
#print("Structs:", RootAST.get_structs())
#print(asciitree.draw_tree(RootAST, ast_children, print_ast_node))
#
# Template rendering
#
__max_str_len = 0
def max_len(str):
global __max_str_len
if len(str) > __max_str_len:
__max_str_len = len(str)
return str
def get_max_len():
global __max_str_len
return __max_str_len
def max_bits(struct):
bits = 0
for s in struct.get_elmts():
if s.bits > bits:
bits = s.bits
return bits
template = jinja2.Template(open(sys.argv[2]).read(), lstrip_blocks=True, trim_blocks=True)
template.globals['max_len'] = max_len
template.globals['get_max_len'] = get_max_len
template.globals['max_bits'] = max_bits
## fixme: root_node_name needs to be mangled (contains ',')
print(template.render(root=RootAST,root_nodes=top_node_names,root_node_name=root_nodes_name))

View file

@ -0,0 +1,72 @@
// generated by generate_yaml.py
//
// Enums first
//
{% for enum in root.get_enums() %}
const struct YamlIdStr {{ enum.name }}[] = {
{% for elmt in enum.get_elmts() %}
{ {{ elmt.value }}, "{{ max_len(elmt.name) }}" },
{% endfor %}
{ 0, NULL }
};
{% endfor %}
//
// Structs last
//
{% for struct in root.get_structs() %}
{% if struct.name.startswith('union_') %}
static const struct YamlNode {{ struct.name }}_elmts[] = {
{% else %}
static const struct YamlNode {{ struct.name }}[] = {
{% if struct.used_in_arrays %}
YAML_IDX,
{% endif%}
{% endif %}
{% for elmt in struct.get_elmts() %}
{% if elmt.skip %}
YAML_PADDING( {{ elmt.bits }} ),
{% elif elmt.type == 'string' %}
YAML_STRING("{{ max_len(elmt.name) }}", {{elmt.length}}),
{% elif elmt.type in ['signed','unsigned'] %}
{% if elmt.f_read and elmt.f_write %}
YAML_{{elmt.type|upper}}_CUST( "{{ max_len(elmt.name) }}", {{ elmt.bits }}, {{ elmt.f_read}}, {{ elmt.f_write}} ),
{% else %}
YAML_{{elmt.type|upper}}( "{{ max_len(elmt.name) }}", {{ elmt.bits }} ),
{% endif %}
{% elif elmt.type == 'enum' %}
YAML_ENUM("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}),
{% elif elmt.type == 'struct' %}
YAML_STRUCT("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}, {{ elmt.func }}),
{% elif elmt.type == 'union' %}
YAML_UNION("{{ max_len(elmt.name) }}", {{elmt.bits}}, {{elmt.var_type}}_elmts, {{ elmt.func}}),
{% elif elmt.type == 'array' %}
YAML_ARRAY("{{ max_len(elmt.name) }}", {{elmt.bits // elmt.length}}, {{elmt.length}}, {{elmt.var_type}}, {{ elmt.func }}),
{% else %}
// name='{{elmt.name}}', type='{{elmt.type}}', bits='{{elmt.bits}}', is_array='{{elmt.is_array}}', var_type='{{elmt.var_type}}', kind='{{elmt.cursor.kind}}' , type.kind='{{elmt.cursor.type.kind}}'
{% endif %}
{% endfor %}
YAML_END
};
{% if struct.name.startswith('union_') and struct.used_in_arrays %}
static const struct YamlNode {{ struct.name }}[] = {
YAML_IDX,
YAML_UNION("u", {{ max_bits(struct) }}, {{ struct.name }}_elmts, {{ struct.func }}),
YAML_END
};
{% endif %}
{% endfor %}
#define MAX_{{ root_node_name | upper }}_STR_LEN {{ get_max_len() }}
{% for tn in root_nodes %}
static const struct YamlNode __{{ tn }}_root_node = YAML_ROOT( struct_{{ tn }} );
const YamlNode* get_{{ tn | lower }}_nodes()
{
return &__{{ tn }}_root_node;
}
{% endfor %}