diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 9de38b130..91449345d 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -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) diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 0ebf0cd3a..1f245c9c4 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -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) diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 18b3aeec3..1fa188c78 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -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]; @@ -266,12 +269,12 @@ PACK(struct ScriptData { PACK(struct RssiAlarmData { int8_t disabled:1; #if defined (PCBNV14) - uint8_t flysky_telemetry:1; // if set for FlySky receivers use native RSSI values instead of rescaled ones + 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 diff --git a/radio/src/gui/colorlcd/layouts/layout1x1.cpp b/radio/src/gui/colorlcd/layouts/layout1x1.cpp index b4ce03f9e..bbbbcd5c2 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x1.cpp @@ -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, diff --git a/radio/src/gui/colorlcd/layouts/layout2+1.cpp b/radio/src/gui/colorlcd/layouts/layout2+1.cpp index 014eb0e01..a205efc66 100644 --- a/radio/src/gui/colorlcd/layouts/layout2+1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2+1.cpp @@ -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); // } diff --git a/radio/src/gui/colorlcd/layouts/layout2x1.cpp b/radio/src/gui/colorlcd/layouts/layout2x1.cpp index 73252c25e..9a7ce49fe 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x1.cpp @@ -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(); // } // diff --git a/radio/src/gui/colorlcd/layouts/layout2x2.cpp b/radio/src/gui/colorlcd/layouts/layout2x2.cpp index 54036176d..453bf9085 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x2.cpp @@ -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(); // } // diff --git a/radio/src/gui/colorlcd/layouts/layout2x4.cpp b/radio/src/gui/colorlcd/layouts/layout2x4.cpp index 322b12c1f..d982c4ddb 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x4.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x4.cpp @@ -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); // } // diff --git a/radio/src/gui/colorlcd/theme.cpp b/radio/src/gui/colorlcd/theme.cpp index f28ab4ce2..dcfa0ff5c 100644 --- a/radio/src/gui/colorlcd/theme.cpp +++ b/radio/src/gui/colorlcd/theme.cpp @@ -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 diff --git a/radio/src/gui/colorlcd/theme.h b/radio/src/gui/colorlcd/theme.h index 7e59825d9..fc659c6db 100644 --- a/radio/src/gui/colorlcd/theme.h +++ b/radio/src/gui/colorlcd/theme.h @@ -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 & 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; diff --git a/radio/src/gui/colorlcd/themes/flysky.cpp b/radio/src/gui/colorlcd/themes/flysky.cpp index 5f63cc9e3..f02427c2f 100644 --- a/radio/src/gui/colorlcd/themes/flysky.cpp +++ b/radio/src/gui/colorlcd/themes/flysky.cpp @@ -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); } } @@ -441,4 +441,4 @@ FlyskyTheme flyskyTheme; #if defined(PCBFLYSKY) ThemeBase * defaultTheme = &flyskyTheme; Theme * theme = &flyskyTheme; -#endif \ No newline at end of file +#endif diff --git a/radio/src/gui/colorlcd/themes/frsky.cpp b/radio/src/gui/colorlcd/themes/frsky.cpp index 157fe1757..8138adc27 100644 --- a/radio/src/gui/colorlcd/themes/frsky.cpp +++ b/radio/src/gui/colorlcd/themes/frsky.cpp @@ -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); } } diff --git a/radio/src/gui/colorlcd/widget.h b/radio/src/gui/colorlcd/widget.h index d854e4680..4a6c7ee9a 100644 --- a/radio/src/gui/colorlcd/widget.h +++ b/radio/src/gui/colorlcd/widget.h @@ -24,15 +24,21 @@ #include #include #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); } } } diff --git a/radio/src/gui/colorlcd/widgets/gauge.cpp b/radio/src/gui/colorlcd/widgets/gauge.cpp index 3dd91a20f..9ebe42243 100644 --- a/radio/src/gui/colorlcd/widgets/gauge.cpp +++ b/radio/src/gui/colorlcd/widgets/gauge.cpp @@ -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; diff --git a/radio/src/gui/colorlcd/widgets/outputs.cpp b/radio/src/gui/colorlcd/widgets/outputs.cpp index 2d3323eb2..1f9fa721a 100644 --- a/radio/src/gui/colorlcd/widgets/outputs.cpp +++ b/radio/src/gui/colorlcd/widgets/outputs.cpp @@ -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[]; diff --git a/radio/src/gui/colorlcd/widgets/text.cpp b/radio/src/gui/colorlcd/widgets/text.cpp index 30d593be6..2ae647bd6 100644 --- a/radio/src/gui/colorlcd/widgets/text.cpp +++ b/radio/src/gui/colorlcd/widgets/text.cpp @@ -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("Text", TextWidget::options); diff --git a/radio/src/gui/colorlcd/widgets/timer.cpp b/radio/src/gui/colorlcd/widgets/timer.cpp index ed900f1ce..c150ab936 100644 --- a/radio/src/gui/colorlcd/widgets/timer.cpp +++ b/radio/src/gui/colorlcd/widgets/timer.cpp @@ -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]; diff --git a/radio/src/gui/colorlcd/widgets/value.cpp b/radio/src/gui/colorlcd/widgets/value.cpp index 67593a255..7587531cc 100644 --- a/radio/src/gui/colorlcd/widgets/value.cpp +++ b/radio/src/gui/colorlcd/widgets/value.cpp @@ -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); } diff --git a/radio/src/gui/colorlcd/widgets_container.h b/radio/src/gui/colorlcd/widgets_container.h index 29d0f427e..37291018a 100644 --- a/radio/src/gui/colorlcd/widgets_container.h +++ b/radio/src/gui/colorlcd/widgets_container.h @@ -59,8 +59,8 @@ class WidgetsContainer: public WidgetsContainerInterface }; struct PersistentData { - ZonePersistentData zones[N]; - ZoneOptionValue options[O]; + ZonePersistentData zones[N]; + 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; diff --git a/radio/src/gui/colorlcd/zone.h b/radio/src/gui/colorlcd/zone.h index 2f3243d40..097058f00 100644 --- a/radio/src/gui/colorlcd/zone.h +++ b/radio/src/gui/colorlcd/zone.h @@ -3,19 +3,20 @@ #define _ZONE_H_ #include +#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_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__ } } #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 diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index 98eb1dd26..b3120d5bd 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -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) { diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 6c87d6d5c..0889cf59e 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -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(); } diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index d4b54ca47..90e748fd4 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -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 diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index 9c6127fbd..1586d3848 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -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; } diff --git a/radio/src/storage/conversions/conversions_218_219.cpp b/radio/src/storage/conversions/conversions_218_219.cpp index e66d27d87..c833a22ca 100644 --- a/radio/src/storage/conversions/conversions_218_219.cpp +++ b/radio/src/storage/conversions/conversions_218_219.cpp @@ -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)); diff --git a/radio/src/storage/conversions/datastructs_218.h b/radio/src/storage/conversions/datastructs_218.h index a3bb72907..37bb64d0c 100644 --- a/radio/src/storage/conversions/datastructs_218.h +++ b/radio/src/storage/conversions/datastructs_218.h @@ -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) diff --git a/radio/src/storage/eeprom_common.h b/radio/src/storage/eeprom_common.h index 1241faf24..a4d33bc55 100644 --- a/radio/src/storage/eeprom_common.h +++ b/radio/src/storage/eeprom_common.h @@ -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 diff --git a/radio/src/storage/eeprom_none.cpp b/radio/src/storage/eeprom_none.cpp new file mode 100644 index 000000000..8a4d78545 --- /dev/null +++ b/radio/src/storage/eeprom_none.cpp @@ -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) +{ +} diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp index e7a4a2d59..cc63c5299 100644 --- a/radio/src/storage/modelslist.cpp +++ b/radio/src/storage/modelslist.cpp @@ -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]; @@ -126,7 +259,11 @@ bool ModelCell::fetchRfData() error: f_close(&file); - return false; + 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::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::iterator it = categories.begin(); it != categories.end(); ++it) { + for (list::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; } diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index 4593399d3..485c9cc17 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -23,7 +23,11 @@ #include #include + #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); }; @@ -100,6 +108,11 @@ public: { return categories; } + + std::list& getCategories() + { + return categories; + } void setCurrentCategorie(ModelsCategory * cat); @@ -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); diff --git a/radio/src/storage/rambackup.cpp b/radio/src/storage/rambackup.cpp index b5a57c832..ddf761fdb 100644 --- a/radio/src/storage/rambackup.cpp +++ b/radio/src/storage/rambackup.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "rambackup.h" namespace Backup { #define BACKUP diff --git a/radio/src/storage/rambackup.h b/radio/src/storage/rambackup.h new file mode 100644 index 000000000..15176d489 --- /dev/null +++ b/radio/src/storage/rambackup.h @@ -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 diff --git a/radio/src/storage/rlc.cpp b/radio/src/storage/rlc.cpp index 86d1227bd..eb6d02bde 100644 --- a/radio/src/storage/rlc.cpp +++ b/radio/src/storage/rlc.cpp @@ -22,6 +22,8 @@ #include #include "debug.h" +#include "rlc.h" + #define CHECK_DST_SIZE() \ if (cur-dst >= (int)dstsize) { \ TRACE("RLC encoding size too big"); \ diff --git a/radio/src/storage/rlc.h b/radio/src/storage/rlc.h new file mode 100644 index 000000000..5180f9c37 --- /dev/null +++ b/radio/src/storage/rlc.h @@ -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 diff --git a/radio/src/storage/sdcard_common.cpp b/radio/src/storage/sdcard_common.cpp new file mode 100644 index 000000000..ac433f7ac --- /dev/null +++ b/radio/src/storage/sdcard_common.cpp @@ -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(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(); +} + diff --git a/radio/src/storage/sdcard_common.h b/radio/src/storage/sdcard_common.h new file mode 100644 index 000000000..5533e004a --- /dev/null +++ b/radio/src/storage/sdcard_common.h @@ -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_ diff --git a/radio/src/storage/sdcard_raw.cpp b/radio/src/storage/sdcard_raw.cpp index 5e86b0901..1c4980ae8 100644 --- a/radio/src/storage/sdcard_raw.cpp +++ b/radio/src/storage/sdcard_raw.cpp @@ -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(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); -} diff --git a/radio/src/storage/sdcard_raw.h b/radio/src/storage/sdcard_raw.h index 15e3346a5..ed34d8226 100644 --- a/radio/src/storage/sdcard_raw.h +++ b/radio/src/storage/sdcard_raw.h @@ -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 diff --git a/radio/src/storage/sdcard_yaml.cpp b/radio/src/storage/sdcard_yaml.cpp new file mode 100644 index 000000000..1e2691fb4 --- /dev/null +++ b/radio/src/storage/sdcard_yaml.cpp @@ -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= (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_ diff --git a/radio/src/storage/yaml/CMakeLists.txt b/radio/src/storage/yaml/CMakeLists.txt new file mode 100644 index 000000000..0d24f7050 --- /dev/null +++ b/radio/src/storage/yaml/CMakeLists.txt @@ -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 +) diff --git a/radio/src/storage/yaml/yaml_bits.cpp b/radio/src/storage/yaml/yaml_bits.cpp new file mode 100644 index 000000000..d64b66508 --- /dev/null +++ b/radio/src/storage/yaml/yaml_bits.cpp @@ -0,0 +1,137 @@ +#include +#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; +} + diff --git a/radio/src/storage/yaml/yaml_bits.h b/radio/src/storage/yaml/yaml_bits.h new file mode 100644 index 000000000..c71d55be8 --- /dev/null +++ b/radio/src/storage/yaml/yaml_bits.h @@ -0,0 +1,20 @@ +#ifndef _yaml_bits_h_ +#define _yaml_bits_h_ + +#include + +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 diff --git a/radio/src/storage/yaml/yaml_datastructs.cpp b/radio/src/storage/yaml/yaml_datastructs.cpp new file mode 100644 index 000000000..c271f31e8 --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs.cpp @@ -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 diff --git a/radio/src/storage/yaml/yaml_datastructs.h b/radio/src/storage/yaml/yaml_datastructs.h new file mode 100644 index 000000000..90961959a --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs.h @@ -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 diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp new file mode 100644 index 000000000..6d7c2478e --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -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; igvars[i] != GVAR_MAX+1; + } + + return is_active; +} diff --git a/radio/src/storage/yaml/yaml_datastructs_x10.cpp b/radio/src/storage/yaml/yaml_datastructs_x10.cpp new file mode 100644 index 000000000..c0d4be228 --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_x10.cpp @@ -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; +} + diff --git a/radio/src/storage/yaml/yaml_datastructs_x12s.cpp b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp new file mode 100644 index 000000000..5da72c704 --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_x12s.cpp @@ -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; +} + diff --git a/radio/src/storage/yaml/yaml_defs.h b/radio/src/storage/yaml/yaml_defs.h new file mode 100644 index 000000000..24d995808 --- /dev/null +++ b/radio/src/storage/yaml/yaml_defs.h @@ -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 diff --git a/radio/src/storage/yaml/yaml_modelslist.cpp b/radio/src/storage/yaml/yaml_modelslist.cpp new file mode 100644 index 000000000..00f7acbe4 --- /dev/null +++ b/radio/src/storage/yaml/yaml_modelslist.cpp @@ -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& 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; +} diff --git a/radio/src/storage/yaml/yaml_modelslist.h b/radio/src/storage/yaml/yaml_modelslist.h new file mode 100644 index 000000000..04ac66f12 --- /dev/null +++ b/radio/src/storage/yaml/yaml_modelslist.h @@ -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 diff --git a/radio/src/storage/yaml/yaml_node.h b/radio/src/storage/yaml/yaml_node.h new file mode 100644 index 000000000..6487eeeb4 --- /dev/null +++ b/radio/src/storage/yaml/yaml_node.h @@ -0,0 +1,174 @@ +#ifndef _node_h_ +#define _node_h_ + +#include +#include + +#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 diff --git a/radio/src/storage/yaml/yaml_parser.cpp b/radio/src/storage/yaml/yaml_parser.cpp new file mode 100644 index 000000000..50fc02a2c --- /dev/null +++ b/radio/src/storage/yaml/yaml_parser.cpp @@ -0,0 +1,256 @@ +#include +#include +#include + +#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; +} + diff --git a/radio/src/storage/yaml/yaml_parser.h b/radio/src/storage/yaml/yaml_parser.h new file mode 100644 index 000000000..85c2ae5b3 --- /dev/null +++ b/radio/src/storage/yaml/yaml_parser.h @@ -0,0 +1,79 @@ +#ifndef _yaml_parser_h_ +#define _yaml_parser_h_ + +#include + +#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 diff --git a/radio/src/storage/yaml/yaml_tree_walker.cpp b/radio/src/storage/yaml/yaml_tree_walker.cpp new file mode 100644 index 000000000..89d669939 --- /dev/null +++ b/radio/src/storage/yaml/yaml_tree_walker.cpp @@ -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 + +#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("", 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(""); + 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); + 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; itoParent(); +} + +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; +} + diff --git a/radio/src/storage/yaml/yaml_tree_walker.h b/radio/src/storage/yaml/yaml_tree_walker.h new file mode 100644 index 000000000..94a014284 --- /dev/null +++ b/radio/src/storage/yaml/yaml_tree_walker.h @@ -0,0 +1,122 @@ +#ifndef _YAML_TREE_WALKER_H_ +#define _YAML_TREE_WALKER_H_ + +#include +#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 diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 7174cadfc..41502fb75 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -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") diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 1ac470fa3..e31f9c315 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -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 diff --git a/radio/src/targets/simu/simufatfs.cpp b/radio/src/targets/simu/simufatfs.cpp index 26f157257..93d8fa8d9 100644 --- a/radio/src/targets/simu/simufatfs.cpp +++ b/radio/src/targets/simu/simufatfs.cpp @@ -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; } } diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt index cb207e10a..36de9dcc9 100644 --- a/radio/src/targets/sky9x/CMakeLists.txt +++ b/radio/src/targets/sky9x/CMakeLists.txt @@ -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) diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 57ca6962e..3be5e3457 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -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) diff --git a/radio/src/telemetry/frsky_pxx2.cpp b/radio/src/telemetry/frsky_pxx2.cpp index 776de975e..7f347fa0a 100644 --- a/radio/src/telemetry/frsky_pxx2.cpp +++ b/radio/src/telemetry/frsky_pxx2.cpp @@ -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]; diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index 78fcac1ea..1cea88d9e 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -84,7 +84,7 @@ PACK(struct CellValue void set(uint16_t newValue) { if (newValue > 50) { - value = value; + value = newValue; state = 1; } } diff --git a/radio/src/thirdparty/libACCESS b/radio/src/thirdparty/libACCESS index 79a6921d2..1bae46726 160000 --- a/radio/src/thirdparty/libACCESS +++ b/radio/src/thirdparty/libACCESS @@ -1 +1 @@ -Subproject commit 79a6921d2386236a44e87554195bf41dc412b445 +Subproject commit 1bae467262bbe8232111a6baee7195850cef2531 diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 24ef58483..385c51175 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 24ef5848392ac2a6196f97d277ba54ded8965e4c +Subproject commit 385c511755dd9ba5814a9bf46ceb0ce499efd162 diff --git a/radio/util/dump_ast.py b/radio/util/dump_ast.py new file mode 100644 index 000000000..48aa9fa52 --- /dev/null +++ b/radio/util/dump_ast.py @@ -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)) diff --git a/radio/util/dump_ast_yaml.py b/radio/util/dump_ast_yaml.py new file mode 100644 index 000000000..33201e54a --- /dev/null +++ b/radio/util/dump_ast_yaml.py @@ -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() diff --git a/radio/util/generate_yaml.py b/radio/util/generate_yaml.py new file mode 100644 index 000000000..fa4733ae3 --- /dev/null +++ b/radio/util/generate_yaml.py @@ -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)) diff --git a/radio/util/yaml_parser.tmpl b/radio/util/yaml_parser.tmpl new file mode 100644 index 000000000..b6b84a905 --- /dev/null +++ b/radio/util/yaml_parser.tmpl @@ -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 %}