diff --git a/src/config/model.c b/src/config/model.c index 1b9a3dd2c8..7e3c09485e 100644 --- a/src/config/model.c +++ b/src/config/model.c @@ -32,7 +32,7 @@ struct Model Model; /*set this to write all model data even if it is the same as the default */ static u32 crc32; -const char * const MODEL_TYPE_VAL[MODELTYPE_LAST] = { "heli", "plane", "multi" }; +static const char * const MODEL_TYPE_VAL[MODELTYPE_LAST] = { "heli", "plane", "multi" }; const u8 RADIO_TX_POWER_COUNT[TX_MODULE_LAST] = { // number of power settings 8, // CYRF6936, 7, // A7105, diff --git a/src/config/model.h b/src/config/model.h index 3a2c28bf18..ec9c6f8bd7 100644 --- a/src/config/model.h +++ b/src/config/model.h @@ -20,7 +20,9 @@ extern const char MODEL_NAME[]; extern const char MODEL_ICON[]; extern const char MODEL_TYPE[]; +extern const char MODEL_MIXERMODE[]; extern const char MODEL_TEMPLATE[]; +extern const char MODEL_AUTOMAP[]; #define UNKNOWN_ICON ("media/noicon" IMG_EXT) //This cannot be computed, and must be manually updated diff --git a/src/target/tx/other/test/old_model.c b/src/target/tx/other/test/old_model.c new file mode 100644 index 0000000000..d1feb298bd --- /dev/null +++ b/src/target/tx/other/test/old_model.c @@ -0,0 +1,1475 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation 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. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#include "common.h" +#include "config/model.h" +#include "telemetry.h" +#include "config/tx.h" +#include "music.h" +#include "extended_audio.h" + +#include +#include +extern const u8 EATRG0[PROTO_MAP_LEN]; + +extern struct Model Model; +/*set this to write all model data even if it is the same as the default */ +static u32 crc32; +static const char * const MODEL_TYPE_VAL[MODELTYPE_LAST] = { "heli", "plane", "multi" }; + +#define MATCH_SECTION(s) (strcasecmp(section, s) == 0) +#define MATCH_START(x,y) (strncasecmp(x, y, sizeof(y)-1) == 0) +#define MATCH_KEY(s) (strcasecmp(name, s) == 0) +#define MATCH_VALUE(s) (strcasecmp(value, s) == 0) +#define NUM_STR_ELEMS(s) (sizeof(s) / sizeof(char *)) + +#define WRITE_FULL_MODEL 0 +static u8 auto_map; + +/* Section: Radio */ +static const char SECTION_RADIO[] = "radio"; + +static const char RADIO_PROTOCOL[] = "protocol"; +#if HAS_VIDEO +static const char RADIO_VIDEOSRC[] = "videosrc"; +static const char RADIO_VIDEOCH[] = "videoch"; +static const char RADIO_VIDEOCONTRAST[] = "videocontrast"; +static const char RADIO_VIDEOBRIGHTNESS[] = "videobrightness"; +#endif + +static const char RADIO_NUM_CHANNELS[] = "num_channels"; +static const char RADIO_FIXED_ID[] = "fixed_id"; + +static const char RADIO_TX_POWER[] = "tx_power"; +#if HAS_EXTENDED_TELEMETRY +static const char RADIO_GROUND_LEVEL[] = "ground_level"; +#endif // HAS_EXTENDED_TELEMETRY + +static const char SECTION_PROTO_OPTS[] = "protocol_opts"; +/* Section: Mixer */ +static const char SECTION_MIXER[] = "mixer"; + +static const char MIXER_SOURCE[] = "src"; +static const char MIXER_DEST[] = "dest"; +static const char MIXER_SWITCH[] = "switch"; +static const char MIXER_SCALAR[] = "scalar"; +static const char MIXER_OFFSET[] = "offset"; +static const char MIXER_USETRIM[] = "usetrim"; + +static const char MIXER_MUXTYPE[] = "muxtype"; +static const char * const MIXER_MUXTYPE_VAL[MUX_LAST] = { + "replace", "multiply", "add", "max", "min", "delay", +#if HAS_EXTENDED_AUDIO + "beep","voice", +#endif +}; + +static const char MIXER_CURVETYPE[] = "curvetype"; +static const char * const MIXER_CURVETYPE_VAL[CURVE_MAX+1] = { + "none", "fixed", "min/max", "zero/max", "greater-than-0", "less-than-0", "absval", + "expo", "deadband", "3point", "5point", "7point", "9point", "11point", "13point" }; +static const char MIXER_CURVE_POINTS[] = "points"; +static const char MIXER_CURVE_SMOOTH[] = "smooth"; + +/* Section: Channel */ +static const char SECTION_CHANNEL[] = "channel"; + +static const char CHAN_DISPLAY_FORMAT[] = "display-format"; +static const char CHAN_DISPLAY_SCALE[] = "display-scale"; +static const char CHAN_LIMIT_REVERSE[] = "reverse"; +static const char CHAN_LIMIT_SAFETYSW[] = "safetysw"; +static const char CHAN_LIMIT_SAFETYVAL[] = "safetyval"; +static const char CHAN_LIMIT_FAILSAFE[] = "failsafe"; +static const char CHAN_LIMIT_MAX[] = "max"; +static const char CHAN_LIMIT_MIN[] = "min"; +static const char CHAN_LIMIT_SPEED[] = "speed"; +static const char CHAN_SUBTRIM[] = "subtrim"; +static const char CHAN_SCALAR_NEG[] = "scalar-"; +#define CHAN_SCALAR MIXER_SCALAR +#define CHAN_TEMPLATE MODEL_TEMPLATE +static const char * const CHAN_TEMPLATE_VAL[MIXERTEMPLATE_MAX+1] = + { "none", "simple", "expo_dr", "complex", "cyclic1", "cyclic2", "cyclic3" }; + +/* Section: Virtual Channel */ +static const char SECTION_VIRTCHAN[] = "virtchan"; +#define VCHAN_TEMPLATE CHAN_TEMPLATE +#define VCHAN_TEMPLATE_VAL CHAN_TEMPLATE_VAL +#define VCHAN_NAME MODEL_NAME + +/* Section: PPM-In */ +static const char SECTION_PPMIN[] = "ppm-in"; +static const char PPMIN_MAP[] = "map"; +static const char PPMIN_MODE[] = "mode"; +static const char * const PPMIN_MODE_VALUE[4] = {"none", "channel", "stick", "extend"}; +static const char PPMIN_CENTERPW[] = "centerpw"; +static const char PPMIN_DELTAPW[] = "deltapw"; +#define PPMIN_NUM_CHANNELS RADIO_NUM_CHANNELS +#define PPMIN_SWITCH MIXER_SWITCH + +/* Section: Trim */ +static const char SECTION_TRIM[] = "trim"; + +#define TRIM_SOURCE MIXER_SOURCE +static const char TRIM_POS[] = "pos"; +static const char TRIM_NEG[] = "neg"; +static const char TRIM_STEP[] = "step"; +static const char TRIM_VALUE[] = "value"; +#define TRIM_SWITCH MIXER_SWITCH + +/* Section: Heli */ +static const char SECTION_SWASH[] = "swash"; +#define SWASH_TYPE MODEL_TYPE +static const char SWASH_AIL_INV[] = "ail_inv"; +static const char SWASH_ELE_INV[] = "ele_inv"; +static const char SWASH_COL_INV[] = "col_inv"; +static const char SWASH_AILMIX[] = "ail_mix"; +static const char SWASH_ELEMIX[] = "ele_mix"; +static const char SWASH_COLMIX[] = "col_mix"; + +/* Section: Timer */ +static const char SECTION_TIMER[] = "timer"; + +#define TIMER_SOURCE MIXER_SOURCE +#define TIMER_TYPE MODEL_TYPE +static const char * const TIMER_TYPE_VAL[TIMER_LAST] = { + [TIMER_STOPWATCH] = "stopwatch", + [TIMER_STOPWATCH_PROP] = "stop-prop", + [TIMER_COUNTDOWN] = "countdown", + [TIMER_COUNTDOWN_PROP] = "cntdn-prop", + [TIMER_PERMANENT] = "permanent", + }; +static const char TIMER_TIME[] = "time"; +static const char TIMER_RESETSRC[] = "resetsrc"; +#if HAS_PERMANENT_TIMER +static const char PERMANENT_TIMER[] = "permanent_timer"; +#endif +static const char TIMER_VAL[] = "val"; + +/* Section: Safety */ +static const char SECTION_SAFETY[] = "safety"; +static const char * const SAFETY_VAL[SAFE_MAX+1] = { "none", "min", "zero", "max" }; + +/* Section: Telemetry */ +static const char SECTION_TELEMALARM[] = "telemalarm"; +static const char TELEM_SRC[] = "source"; +static const char TELEM_ABOVE[] = "above"; +static const char TELEM_VALUE[] = "value"; +static const char TELEM_THRESHOLD[] ="threshold"; + +#if HAS_DATALOG +/* Section: Datalog */ +static const char SECTION_DATALOG[] = "datalog"; +static const char DATALOG_RATE[] = "rate"; +#define DATALOG_SWITCH MIXER_SWITCH +#define DATALOG_SOURCE TELEM_SRC +#endif + +/* Section: Gui-QVGA */ +#define STRINGIFY(x) _STRINGIFY(x) +#define _STRINGIFY(x) #x +static const char SECTION_GUI[] = "gui-" STRINGIFY(LCD_WIDTH) "x" STRINGIFY(LCD_HEIGHT); +static const char GUI_QUICKPAGE[] = "quickpage"; + +#if HAS_EXTENDED_AUDIO +/* Section: Music */ +static const char SECTION_VOICE[] = "voice"; +static const char * const VOICE_TELEMALARM[TELEM_NUM_ALARMS] = + { "telemalarm1", "telemalarm2", "telemalarm3", "telemalarm4", "telemalarm5", "telemalarm6" }; +static const char * const VOICE_TIMER[NUM_TIMERS] = + { "timer1", "timer2", "timer3", "timer4" }; + +#endif + + +static s8 mapstrcasecmp(const char *s1, const char *s2) +{ + int i = 0; + while(1) { + if(s1[i] == s2[i] + || (s2[i] >= 'a' && s1[i] + ('a'-'A') == s2[i]) + || (s1[i] >= 'a' && s2[i] + ('a'-'A') == s1[i]) + || (s2[i] == ' ' && s1[i] == '_') + || (s1[i] == ' ' && s2[i] == '_')) + { + if(s1[i] == '\0') + return 0; + i++; + continue; + } + return(s1[i] < s2[i] ? -1 : 1); + } +} +static u8 get_source(const char *section, const char *value) +{ + unsigned i; + unsigned val; + const char *ptr = (value[0] == '!') ? value + 1 : value; + const char *tmp; + char cmp[10]; + for (i = 0; i <= NUM_SOURCES; i++) { + if(mapstrcasecmp(INPUT_SourceNameReal(cmp, i), ptr) == 0) { + #if defined(HAS_SWITCHES_NOSTOCK) && HAS_SWITCHES_NOSTOCK + #define SWITCH_NOSTOCK ((1 << INP_HOLD0) | (1 << INP_HOLD1) | \ + (1 << INP_FMOD0) | (1 << INP_FMOD1)) + if ((Transmitter.ignore_src & SWITCH_NOSTOCK) == SWITCH_NOSTOCK) { + if(mapstrcasecmp("FMODE0", ptr) == 0 || + mapstrcasecmp("FMODE1", ptr) == 0 || + mapstrcasecmp("HOLD0", ptr) == 0 || + mapstrcasecmp("HOLD1", ptr) == 0) + break; + } + #endif //HAS_SWITCHES_NOSTOCK + return ((ptr == value) ? 0 : 0x80) | i; + } + } + for (i = 0; i < 4; i++) { + if(mapstrcasecmp(tx_stick_names[i], ptr) == 0) { + return ((ptr == value) ? 0 : 0x80) | (i + 1); + } + } + i = 0; + while((tmp = INPUT_MapSourceName(i++, &val))) { + if(mapstrcasecmp(tmp, ptr) == 0) { + return ((ptr == value) ? 0 : 0x80) | val; + } + } + printf("%s: Could not parse Source %s\n", section, value); + return 0; +} + +static u8 get_button(const char *section, const char *value) +{ + u8 i; + for (i = 0; i <= NUM_TX_BUTTONS; i++) { + if(strcasecmp(INPUT_ButtonName(i), value) == 0) { + return i; + } + } + printf("%s: Could not parse Button %s\n", section, value); + return 0; +} + +static int handle_proto_opts(struct Model *m, const char* key, const char* value, const char **opts) +{ + const char **popts = opts; + int idx = 0; + while(*popts) { + if(mapstrcasecmp(*popts, key) == 0) { + popts++; + int start = exact_atoi(popts[0]); + int end = exact_atoi(popts[1]); + int is_num = ((start != 0 || end != 0) && (popts[2] == 0 || (popts[3] == 0 && exact_atoi(popts[2]) != 0))) ? 1 : 0; + if(is_num) { + m->proto_opts[idx] = atoi(value); + return 1; + } + int val = 0; + while(popts[val]) { + if(mapstrcasecmp(popts[val], value) == 0) { + m->proto_opts[idx] = val; + return 1; + } + val++; + } + printf("Unknown protocol option '%s' for '%s'\n", value, key); + return 1; + } + //Find end of options + while(*popts) { + popts++; + } + popts++; //Go to next option + idx++; + } + return 0; +} + +enum { + S8, + U8, + S16 +}; +static const char * parse_partial_int_list(const char *ptr, void *vals, int *max_count, int type) +{ + //const char *origptr = ptr; + int value_int = 0; + int idx = 0; + int sign = 0; + + while(1) { + if(*ptr == ',' || *ptr == '\0') { + value_int = value_int * (sign ? -1 : 1); + if (type == S8) { + if (value_int > 127) + value_int = 127; + else if (value_int < -127) + value_int = -127; + ((s8 *)vals)[idx] = value_int; + } else if (type == U8) { + if (value_int > 255) + value_int = 255; + else if (value_int < 0) + value_int = 0; + ((u8 *)vals)[idx] = value_int; + } else { + ((s16 *)vals)[idx] = value_int; + } + sign = 0; + value_int = 0; + idx++; + --*max_count; + if (*max_count == 0 || *ptr == '\0') + return ptr; + } else if(*ptr == '-') { + sign = 1; + } else if (*ptr >= '0' && *ptr <= '9') { + value_int = value_int * 10 + (*ptr - '0'); + } else { + //printf("Bad value '%c' in '%s'\n", *ptr, origptr); + return ptr; + } + ptr++; + } +} + +static int parse_int_list(const char *ptr, void *vals, int max_count, int type) +{ + int count = max_count; + parse_partial_int_list(ptr, vals, &count, type); + return max_count - count; +} + +static void create_element(struct elem *elem, int type, s16 *data) +{ + //int x, int y, int src, int e0, int e1, int e2) + ELEM_SET_X(*elem, data[0]); + ELEM_SET_Y(*elem, data[1]); + ELEM_SET_TYPE(*elem, type); + elem->src = data[5]; + elem->extra[0] = data[2]; + elem->extra[1] = data[3]; + elem->extra[2] = data[4]; +} + +static int layout_ini_handler(void* user, const char* section, const char* name, const char* value) +{ + struct Model *m = (struct Model *)user; + u16 i; + int offset_x = 0, offset_y = 0; + CLOCK_ResetWatchdog(); + int idx; + if (MATCH_START(name, GUI_QUICKPAGE)) { + u8 idx = name[9] - '1'; + if (idx >= NUM_QUICKPAGES) { + printf("%s: Only %d quickpages are supported\n", section, NUM_QUICKPAGES); + return 1; + } + int max = PAGE_GetNumPages(); + for(i = 0; i < max; i++) { + if(mapstrcasecmp(PAGE_GetName(i), value) == 0) { + m->pagecfg2.quickpage[idx] = i; + return 1; + } + } + printf("%s: Unknown page '%s' for quickpage%d\n", section, value, idx+1); + return 1; + } +#ifdef ENABLE_320x240_GUI + static u8 seen_res = 0; + enum { + LOWRES = 1, + HIRES, + }; + if (! MATCH_SECTION(SECTION_GUI)) { + if(MATCH_SECTION("gui-320x240") + && (! ELEM_USED(Model.pagecfg2.elem[0]) || seen_res != HIRES)) + { + seen_res = LOWRES; + offset_x = (LCD_WIDTH - 320) / 2; + offset_y = (LCD_HEIGHT - 240) / 2; + } else + return 1; + } else { + if (seen_res == LOWRES) { + memset(&Model.pagecfg2.elem, 0, sizeof(Model.pagecfg2.elem)); + } + seen_res = HIRES; + } +#else + if (! MATCH_SECTION(SECTION_GUI)) + return 1; +#endif + for (idx = 0; idx < NUM_ELEMS; idx++) { + if (! ELEM_USED(Model.pagecfg2.elem[idx])) + break; + } + + if (idx == NUM_ELEMS) { + printf("No free element available (max = %d)\n", NUM_ELEMS); + return 1; + } + int type; + for (type = 0; type < ELEM_LAST; type++) + if(mapstrcasecmp(name, GetElemName(type)) == 0) + break; + if (type == ELEM_LAST) + return 1; + int count = 5; + s16 data[6] = {0}; + const char *ptr = parse_partial_int_list(value, data, &count, S16); + data[0] += offset_x; + data[1] += offset_y; + if (count > 3) { + printf("Could not parse coordinates from %s=%s\n", name,value); + return 1; + } + switch(type) { + //case ELEM_MODEL: //x, y + case ELEM_VTRIM: //x, y, src + case ELEM_HTRIM: //x, y, src + data[5] = data[2]; + data[2] = 0; + break; + case ELEM_SMALLBOX: //x, y, src + case ELEM_BIGBOX: //x. y. src + { + s16 src = -1; + char str[20]; + if (count != 3) + return 1; +#if HAS_RTC + for(i = 0; i < NUM_RTC; i++) { + if(mapstrcasecmp(ptr, RTC_Name(str, i)) == 0) { + src = i + 1; + break; + } + } +#endif + if (src == -1) { + for(i = 0; i < NUM_TIMERS; i++) { + if(mapstrcasecmp(ptr, TIMER_Name(str, i)) == 0) { + src = i + 1 + NUM_RTC; + break; + } + } + } + if (src == -1) { + for(i = 0; i < NUM_TELEM; i++) { + if(mapstrcasecmp(ptr, TELEMETRY_Name(str, i+1)) == 0) { + src = i + 1 + NUM_RTC + NUM_TIMERS; + break; + } + } + } + if (src == -1) { + u8 newsrc = get_source(section, ptr); + if(newsrc >= NUM_INPUTS) { + src = newsrc - (NUM_INPUTS + 1 - (NUM_RTC + NUM_TIMERS + NUM_TELEM + 1)); + } + } + if (src == -1) + src = 0; + data[5] = src; + break; + } + case ELEM_BAR: //x, y, src + { + if (count != 3) + return 1; + u8 src = get_source(section, ptr); + if (src < NUM_INPUTS) + src = 0; + data[5] = src - NUM_INPUTS; + break; + } + case ELEM_TOGGLE: //x, y, tgl0, tgl1, tgl2, src + { + if(count) + return 1; + for (int j = 0; j <= NUM_SOURCES; j++) { + char cmp[10]; + if(mapstrcasecmp(INPUT_SourceNameAbbrevSwitchReal(cmp, j), ptr+1) == 0) { + data[5] = j; + break; + } + } + break; + } + } + create_element(&m->pagecfg2.elem[idx], type, data); + return 1; +} + +struct struct_map {const char *str; u16 offset; u16 defval;}; +#define MAPSIZE(x) (sizeof(x) / sizeof(struct struct_map)) +#define OFFSET(s,v) (((long)(&s.v) - (long)(&s)) | ((sizeof(s.v)-1) << 13)) +#define OFFSETS(s,v) (((long)(&s.v) - (long)(&s)) | ((sizeof(s.v)+3) << 13)) +#define OFFSET_SRC(s,v) (((long)(&s.v) - (long)(&s)) | (2 << 13)) +#define OFFSET_BUT(s,v) (((long)(&s.v) - (long)(&s)) | (6 << 13)) +#if HAS_PERMANENT_TIMER +static const struct struct_map _secnone[] = +{ + {PERMANENT_TIMER, OFFSET(Model, permanent_timer), 0}, +}; +#endif +static const struct struct_map _secradio[] = { + {RADIO_NUM_CHANNELS, OFFSET(Model, num_channels), 0}, + {RADIO_FIXED_ID, OFFSET(Model, fixed_id), 0}, +#if HAS_VIDEO + {RADIO_VIDEOSRC, OFFSET_SRC(Model, videosrc), 0}, + {RADIO_VIDEOCH, OFFSET(Model, videoch), 0}, + {RADIO_VIDEOCONTRAST,OFFSET(Model, video_contrast), 0}, + {RADIO_VIDEOBRIGHTNESS,OFFSET(Model, video_brightness), 0}, +#endif +#if HAS_EXTENDED_TELEMETRY + {RADIO_GROUND_LEVEL, OFFSET(Model, ground_level), 0}, +#endif +}; +static const struct struct_map _secmixer[] = { + {MIXER_SWITCH, OFFSET_SRC(Model.mixers[0], sw), 0}, + {MIXER_SCALAR, OFFSETS(Model.mixers[0], scalar), 100}, + {MIXER_OFFSET, OFFSETS(Model.mixers[0], offset), 0}, +}; +static const struct struct_map _seclimit[] = { + {CHAN_LIMIT_SAFETYSW, OFFSET_SRC(Model.limits[0], safetysw), 0}, + {CHAN_LIMIT_SAFETYVAL, OFFSETS(Model.limits[0], safetyval), 0}, + {CHAN_LIMIT_MAX, OFFSET(Model.limits[0], max), DEFAULT_SERVO_LIMIT}, + {CHAN_LIMIT_SPEED, OFFSET(Model.limits[0], speed), 0}, + {CHAN_SCALAR, OFFSET(Model.limits[0], servoscale), 100}, + {CHAN_SCALAR_NEG, OFFSET(Model.limits[0], servoscale_neg), 0}, + {CHAN_SUBTRIM, OFFSETS(Model.limits[0], subtrim), 0}, + {CHAN_DISPLAY_SCALE, OFFSETS(Model.limits[0], displayscale), DEFAULT_DISPLAY_SCALE}, +}; +static const struct struct_map _sectrim[] = { + {TRIM_SOURCE, OFFSET_SRC(Model.trims[0], src), 0xFFFF}, + {TRIM_POS, OFFSET_BUT(Model.trims[0], pos), 0}, + {TRIM_NEG, OFFSET_BUT(Model.trims[0], neg), 0}, + {TRIM_STEP, OFFSET(Model.trims[0], step), 1}, +}; +static const struct struct_map _secswash[] = { + {SWASH_AILMIX, OFFSET(Model, swashmix[0]), 60}, + {SWASH_ELEMIX, OFFSET(Model, swashmix[1]), 60}, + {SWASH_COLMIX, OFFSET(Model, swashmix[2]), 60}, +}; +static const struct struct_map _sectimer[] = { + {TIMER_TIME, OFFSET(Model.timer[0], timer), 0xFFFF}, + {TIMER_VAL, OFFSET(Model.timer[0], val), 0xFFFF}, + {TIMER_SOURCE, OFFSET_SRC(Model.timer[0], src), 0}, + {TIMER_RESETSRC, OFFSET_SRC(Model.timer[0], resetsrc), 0}, +}; +static const struct struct_map _secppm[] = { + {PPMIN_CENTERPW, OFFSET(Model, ppmin_centerpw), 0}, + {PPMIN_DELTAPW, OFFSET(Model, ppmin_deltapw), 0}, + {PPMIN_SWITCH, OFFSET_SRC(Model, train_sw), 0xFFFF}, +}; +static int ini_handler(void* user, const char* section, const char* name, const char* value) +{ + int value_int = atoi(value); + struct Model *m = (struct Model *)user; +int assign_int(void* ptr, const struct struct_map *map, int map_size) +{ + for(int i = 0; i < map_size; i++) { + if(MATCH_KEY(map[i].str)) { + int size = map[i].offset >> 13; + int offset = map[i].offset & 0x1FFF; + switch(size) { + case 0: + *((u8 *)((long)ptr + offset)) = value_int; break; + case 1: + *((u16 *)((long)ptr + offset)) = value_int; break; + case 2: + *((u8 *)((long)ptr + offset)) = get_source(section, value); break; + case 3: + *((u32 *)((long)ptr + offset)) = value_int; break; + case 4: + *((s8 *)((long)ptr + offset)) = value_int; break; + case 5: + *((s16 *)((long)ptr + offset)) = value_int; break; + case 6: + *((u8 *)((long)ptr + offset)) = get_button(section, value); break; + case 7: + *((s32 *)((long)ptr + offset)) = value_int; break; + } + return 1; + } + } + return 0; +} + CLOCK_ResetWatchdog(); + unsigned i; + if (MATCH_SECTION("")) { + if(MATCH_KEY(MODEL_NAME)) { + strlcpy(m->name, value, sizeof(m->name)-1); + return 1; + } + if(MATCH_KEY(MODEL_TEMPLATE)) { + //A dummy rule + return 1; + } + if (MATCH_KEY(MODEL_ICON)) { + CONFIG_ParseIconName(m->icon, value); + return 1; + } +#if HAS_PERMANENT_TIMER + if(assign_int(&Model, _secnone, MAPSIZE(_secnone))) + return 1; +#endif + if (MATCH_KEY(MODEL_TYPE)) { + for (i = 0; i < NUM_STR_ELEMS(MODEL_TYPE_VAL); i++) { + if (MATCH_VALUE(MODEL_TYPE_VAL[i])) { + m->type = i; + return 1; + } + } + return 0; + } + if (MATCH_KEY(MODEL_AUTOMAP)) { + auto_map = atoi(value); + return 1; + } + if (MATCH_KEY(MODEL_MIXERMODE)) { + for(i = 1; i < 3; i++) { + if(MATCH_VALUE(STDMIXER_ModeName(i))) + m->mixer_mode = i; + } + return 1; + } + } + if (MATCH_SECTION(SECTION_RADIO)) { + if (MATCH_KEY(RADIO_PROTOCOL)) { + for (i = 0; i < PROTOCOL_COUNT; i++) { + if (MATCH_VALUE(PROTOCOL_GetName(i))) { + m->protocol = i; + m->radio = PROTOCOL_GetRadio(i); + PROTOCOL_Load(1); + return 1; + } + } + printf("Unknown protocol: %s\n", value); + return 1; + } + if(assign_int(&Model, _secradio, MAPSIZE(_secradio))) + return 1; + if (MATCH_KEY(RADIO_TX_POWER)) { + if (m->radio == TX_MODULE_LAST) { + m->tx_power = TXPOWER_150mW; + return 1; + } + for (i = 0; i < RADIO_TX_POWER_COUNT[m->radio]; i++) { + if (MATCH_VALUE(radio_tx_power_val(m->radio, i))) { + m->tx_power = i; + return 1; + } + } + printf("Unknown Tx power: %s\n", value); + m->tx_power = RADIO_TX_POWER_COUNT[m->radio]-1; // default to radio maximum + return 1; + } + printf("Unknown Radio Key: %s\n", name); + return 0; + } + if (MATCH_SECTION(SECTION_PROTO_OPTS)) { + const char **opts = PROTOCOL_GetOptions(); + if (!opts || ! *opts) + return 1; + return handle_proto_opts(m, name, value, opts); + } + if (MATCH_START(section, SECTION_MIXER)) { + int idx; + for (idx = 0; idx < NUM_MIXERS; idx++) { + if(m->mixers[idx].src == 0) + break; + } + if (MATCH_KEY(MIXER_SOURCE)) { + if (idx == NUM_MIXERS) { + printf("%s: Only %d mixers are supported\n", section, NUM_MIXERS); + return 1; + } + m->mixers[idx].src = get_source(section, value); + return 1; + } + idx--; + if (MATCH_KEY(MIXER_DEST)) { + m->mixers[idx].dest = get_source(section, value) - NUM_INPUTS - 1; + return 1; + } + if(assign_int(&m->mixers[idx], _secmixer, MAPSIZE(_secmixer))) + return 1; + if (MATCH_KEY(MIXER_USETRIM)) { + MIXER_SET_APPLY_TRIM(&m->mixers[idx], value_int); + return 1; + } + if (MATCH_KEY(MIXER_MUXTYPE)) { + for (i = 0; i < NUM_STR_ELEMS(MIXER_MUXTYPE_VAL); i++) { + if (MATCH_VALUE(MIXER_MUXTYPE_VAL[i])) { + MIXER_SET_MUX(&m->mixers[idx], i); + return 1; + } + } + printf("%s: Unknown Mux type: %s\n", section, value); + return 1; + } + if (MATCH_KEY(MIXER_CURVETYPE)) { + for (i = 0; i < NUM_STR_ELEMS(MIXER_CURVETYPE_VAL); i++) { + if (MATCH_VALUE(MIXER_CURVETYPE_VAL[i])) { + CURVE_SET_TYPE(&m->mixers[idx].curve, i); + return 1; + } + } + printf("%s: Unknown Curve type: %s\n", section, value); + return 1; + } + if (MATCH_KEY(MIXER_CURVE_POINTS)) { + int count = parse_int_list(value, m->mixers[idx].curve.points, MAX_POINTS, S8); + if (count > MAX_POINTS) { + printf("%s: Too many points (max points = %d\n", section, MAX_POINTS); + return 0; + } + return 1; + } + if (MATCH_KEY(MIXER_CURVE_SMOOTH)) { + CURVE_SET_SMOOTHING(&m->mixers[idx].curve, value_int); + return 1; + } + printf("%s: Couldn't parse key: %s\n", section, name); + return 0; + } + if (MATCH_START(section, SECTION_CHANNEL)) { + u8 idx = atoi(section + sizeof(SECTION_CHANNEL)-1); + if (idx == 0) { + printf("Unknown Channel: %s\n", section); + return 0; + } + if (idx > NUM_OUT_CHANNELS) { + printf("%s: Only %d channels are supported\n", section, NUM_OUT_CHANNELS); + return 1; + } + idx--; + if (MATCH_KEY(CHAN_LIMIT_REVERSE)) { + if (value_int) + m->limits[idx].flags |= CH_REVERSE; + else + m->limits[idx].flags &= ~CH_REVERSE; + return 1; + } + if (MATCH_KEY(CHAN_LIMIT_FAILSAFE)) { + if(strcasecmp("off", value) == 0) { + m->limits[idx].flags &= ~CH_FAILSAFE_EN; + } else { + m->limits[idx].failsafe = value_int; + m->limits[idx].flags |= CH_FAILSAFE_EN; + } + return 1; + } + if (MATCH_KEY(CHAN_DISPLAY_FORMAT)) { + strcpy(m->limits[idx].displayformat, value); + return 1; + } + + if(assign_int(&m->limits[idx], _seclimit, MAPSIZE(_seclimit))) + return 1; + if (MATCH_KEY(CHAN_LIMIT_MIN)) { + m->limits[idx].min = -value_int; + return 1; + } + if (MATCH_KEY(CHAN_TEMPLATE)) { + for (i = 0; i < NUM_STR_ELEMS(CHAN_TEMPLATE_VAL); i++) { + if (MATCH_VALUE(CHAN_TEMPLATE_VAL[i])) { + m->templates[idx] = i; + return 1; + } + } + printf("%s: Unknown template: %s\n", section, value); + return 1; + } + printf("%s: Unknown key: %s\n", section, name); + return 0; + } + if (MATCH_START(section, SECTION_VIRTCHAN)) { + u8 idx = atoi(section + sizeof(SECTION_VIRTCHAN)-1); + if (idx == 0) { + printf("Unknown Virtual Channel: %s\n", section); + return 0; + } + if (idx > NUM_VIRT_CHANNELS) { + printf("%s: Only %d virtual channels are supported\n", section, NUM_VIRT_CHANNELS); + return 1; + } + idx = idx + NUM_OUT_CHANNELS - 1; + if (MATCH_KEY(VCHAN_TEMPLATE)) { + for (i = 0; i < NUM_STR_ELEMS(VCHAN_TEMPLATE_VAL); i++) { + if (MATCH_VALUE(VCHAN_TEMPLATE_VAL[i])) { + m->templates[idx] = i; + return 1; + } + } + printf("%s: Unknown template: %s\n", section, value); + return 1; + } + if (MATCH_KEY(VCHAN_NAME)) { + strlcpy(m->virtname[idx - NUM_OUT_CHANNELS], value, sizeof(m->virtname[0])); + return 1; + } + printf("%s: Unknown key: %s\n", section, name); + return 0; + } + if (MATCH_START(section, SECTION_TRIM)) { + u8 idx = atoi(section + sizeof(SECTION_TRIM)-1); + if (idx == 0) { + printf("Unknown Trim: %s\n", section); + return 0; + } + if (idx > NUM_TRIMS) { + printf("%s: Only %d trims are supported\n", section, NUM_TRIMS); + return 1; + } + idx--; + if(assign_int(&m->trims[idx], _sectrim, MAPSIZE(_sectrim))) + return 1; + if (MATCH_KEY(TRIM_SWITCH)) { + for (int i = 0; i <= NUM_SOURCES; i++) { + char cmp[10]; + if(mapstrcasecmp(INPUT_SourceNameAbbrevSwitchReal(cmp, i), value) == 0) { + m->trims[idx].sw = i; + return 1; + } + } + return 1; + } + if (MATCH_KEY(TRIM_VALUE)) { + parse_int_list(value, m->trims[idx].value, 6, S8); + return 1; + } + printf("%s: Unknown trim setting: %s\n", section, name); + return 0; + } + if (MATCH_SECTION(SECTION_SWASH)) { + if (MATCH_KEY(SWASH_TYPE)) { + for (i = SWASH_TYPE_NONE; i <= SWASH_TYPE_90; i++) { + if(strcasecmp(MIXER_SwashType(i), value) == 0) { + m->swash_type = i; + return 1; + } + } + printf("%s: Unknown swash_type: %s\n", section, value); + return 1; + } + if (MATCH_KEY(SWASH_ELE_INV)) { + if (value_int) + m->swash_invert |= 0x01; + return 1; + } + if (MATCH_KEY(SWASH_AIL_INV)) { + if (value_int) + m->swash_invert |= 0x02; + return 1; + } + if (MATCH_KEY(SWASH_COL_INV)) { + if (value_int) + m->swash_invert |= 0x04; + return 1; + } + if(assign_int(m, _secswash, MAPSIZE(_secswash))) + return 1; + } + if (MATCH_START(section, SECTION_TIMER)) { + u8 idx = atoi(section + sizeof(SECTION_TIMER)-1); + if (idx == 0) { + printf("Unknown Timer: %s\n", section); + return 0; + } + if (idx > NUM_TIMERS) { + printf("%s: Only %d timers are supported\n", section, NUM_TIMERS); + return 1; + } + idx--; + if (MATCH_KEY(TIMER_TYPE)) { + for (i = 0; i < NUM_STR_ELEMS(TIMER_TYPE_VAL); i++) { + if (MATCH_VALUE(TIMER_TYPE_VAL[i])) { + m->timer[idx].type = i; + return 1; + } + } + printf("%s: Unknown timer type: %s\n", section, value); + return 1; + } + if(assign_int(&m->timer[idx], _sectimer, MAPSIZE(_sectimer))) + return 1; + } + if (MATCH_START(section, SECTION_TELEMALARM)) { + u8 idx = atoi(section + sizeof(SECTION_TELEMALARM)-1); + if (idx == 0) { + printf("Unknown Telem-alarm: %s\n", section); + return 0; + } + if (idx > TELEM_NUM_ALARMS) { + printf("%s: Only %d timers are supported\n", section, TELEM_NUM_ALARMS); + return 1; + } + struct TelemetryAlarm *alarm = &Model.alarms[idx - 1]; // idx is 1 based + if (MATCH_KEY(TELEM_SRC)) { + char str[20]; + unsigned last = TELEMETRY_GetNumTelemSrc(); + for(i = 1; i <= last; i++) { + if (strcasecmp(TELEMETRY_ShortName(str, i), value) == 0) { + alarm->src = i; + return 1; + } + } + printf("%s: Unknown telemetry src: %s\n", section, value); + return 0; + } + if (MATCH_KEY(TELEM_ABOVE)) { + if (atoi(value)) + alarm->above = 1; + else + alarm->above = 0; + return 1; + } + if (MATCH_KEY(TELEM_VALUE)) { + alarm->value = atoi(value); + return 1; + } + if (MATCH_KEY(TELEM_THRESHOLD)) { + alarm->threshold = atoi(value); + return 1; + } + } +#if HAS_DATALOG + if (MATCH_SECTION(SECTION_DATALOG)) { + if (MATCH_KEY(DATALOG_SWITCH)) { + m->datalog.enable = get_source(section, value); + } else if (MATCH_KEY(DATALOG_RATE)) { + for (i = 0; i < DLOG_RATE_LAST; i++) { + if(mapstrcasecmp(DATALOG_RateString(i), value) == 0) { + m->datalog.rate = i; + break; + } + } + } else if (MATCH_KEY(DATALOG_SOURCE)) { + char cmp[10]; + for (i = 0; i < DLOG_LAST; i++) { + if(mapstrcasecmp(DATALOG_Source(cmp, i), value) == 0) { + m->datalog.source[DATALOG_BYTE(i)] |= 1 << DATALOG_POS(i); + break; + } + } + } + return 1; + } +#endif //HAS_DATALOG + if (MATCH_START(section, SECTION_SAFETY)) { + int found = 0; + u8 src; + if (MATCH_KEY("auto")) { + src = 0; + found = 1; + } else { + src = get_source(section, name); + } + if(found || src) { + u32 i; + for (i = 0; i < NUM_STR_ELEMS(SAFETY_VAL); i++) { + if (MATCH_VALUE(SAFETY_VAL[i])) { + m->safety[src] = i; + return 1; + } + } + } + } + if (MATCH_START(section, "gui-")) { + return layout_ini_handler(user, section, name, value); + } + if (MATCH_SECTION(SECTION_PPMIN)) { + if (MATCH_KEY(PPMIN_NUM_CHANNELS)) { + m->num_ppmin_channels = atoi(value); + return 1; + } + if (MATCH_KEY(PPMIN_MODE)) { + for(i = 0; i < 4; i++) { + if(mapstrcasecmp(PPMIN_MODE_VALUE[i], value) == 0) { + m->ppmin_mode = i; + return 1; + } + } + return 1; + } + if(assign_int(m, _secppm, MAPSIZE(_secppm))) + return 1; + if (MATCH_START(name, PPMIN_MAP)) { + u8 idx = atoi(name + sizeof(PPMIN_MAP)-1) -1; + if (idx < MAX_PPM_IN_CHANNELS) { + m->ppm_map[idx] = get_source(section, value); + if (PPMin_Mode() == PPM_IN_TRAIN1) { + m->ppm_map[idx] = (m->ppm_map[idx] <= NUM_INPUTS) + ? -1 + : m->ppm_map[idx] - (NUM_INPUTS + 1); + } + } + return 1; + } + } +#if HAS_EXTENDED_AUDIO + char src_name[20]; + + if (MATCH_SECTION(SECTION_VOICE)) { + u16 val = atoi(value); + if(val>MAX_VOICEMAP_ENTRIES-1 || voice_map[val].duration == 0 || val < CUSTOM_ALARM_ID) { + printf("%s: Music %s not found in voice.ini or below ID %d\n", section, value, CUSTOM_ALARM_ID); + return 0; + } + for (int i = INP_HAS_CALIBRATION+1; i <= NUM_INPUTS; i++) { + INPUT_SourceName(src_name, i); + if (MATCH_KEY(src_name)) { + m->voice.switches[i - INP_HAS_CALIBRATION - 1].music = val; + return 1; + } + } +#if NUM_AUX_KNOBS + for (int i = 0; i < NUM_AUX_KNOBS; i++) { + INPUT_SourceName(src_name, i + NUM_STICKS + 1); + strcat(src_name, "_UP"); + if (MATCH_KEY(src_name)) { + m->voice.aux[i * 2 + 1].music = val; + return 1; + } + INPUT_SourceName(src_name, i + NUM_STICKS + 1); + strcat(src_name, "_DOWN"); + if (MATCH_KEY(src_name)) { + m->voice.aux[i * 2].music = val; + return 1; + } + } +#endif + for (int i = 0; i < NUM_TIMERS; i++) { + if (MATCH_KEY(VOICE_TIMER[i])) { + m->voice.timer[i].music = val; + return 1; + } + } + for (int i = 0; i < TELEM_NUM_ALARMS; i++) { + if (MATCH_KEY(VOICE_TELEMALARM[i])) { + m->voice.telemetry[i].music = val; + return 1; + } + } + for (int i = 0; i < (NUM_OUT_CHANNELS + NUM_VIRT_CHANNELS); i++) { + INPUT_SourceNameReal(src_name, i + NUM_INPUTS + 1); + if (MATCH_KEY(src_name)) { + m->voice.mixer[i].music = val; + return 1; + } + } + printf("%s: unknown source name '%s'\n", section, name); + return 0; + } +#endif + printf("Unknown Section: '%s'\n", section); + return 0; +} + +static void get_model_file(char *file, u8 model_num) +{ + if (model_num == 0) + sprintf(file, "models/default.ini"); + else + sprintf(file, "models/model%d.ini", model_num); +} + +static void write_int(FILE *fh, void* ptr, const struct struct_map *map, int map_size) +{ + char tmpstr[20]; + for(int i = 0; i < map_size; i++) { + int size = map[i].offset >> 13; + int offset = map[i].offset & 0x1FFF; + int value; + if (map[i].defval == 0xffff) + continue; + switch(size) { + case 0: + case 2: //SRC + case 6: //BUTTON + value = *((u8 *)((long)ptr + offset)); break; + case 1: value = *((u16 *)((long)ptr + offset)); break; + case 3: value = *((u32 *)((long)ptr + offset)); break; + case 4: value = *((s8 *)((long)ptr + offset)); break; + case 5: value = *((s16 *)((long)ptr + offset)); break; + case 7: value = *((s32 *)((long)ptr + offset)); break; + default: continue; + } + if(WRITE_FULL_MODEL || value != map[i].defval) { + if (2 == (size & 0x03)) //2, 6 + fprintf(fh, "%s=%s\n", map[i].str, size == 2 ? INPUT_SourceNameReal(tmpstr, value) : INPUT_ButtonName(value)); + else + fprintf(fh, "%s=%d\n", map[i].str, value); + } + } +} + +static u8 write_mixer(FILE *fh, struct Model *m, u8 channel) +{ + int idx; + int i; + char tmpstr[20]; + u8 changed = 0; + for(idx = 0; idx < NUM_MIXERS; idx++) { + if (! WRITE_FULL_MODEL && (m->mixers[idx].src == 0 || m->mixers[idx].dest != channel)) + continue; + changed = 1; + fprintf(fh, "[%s]\n", SECTION_MIXER); + fprintf(fh, "%s=%s\n", MIXER_SOURCE, INPUT_SourceNameReal(tmpstr, m->mixers[idx].src)); + fprintf(fh, "%s=%s\n", MIXER_DEST, INPUT_SourceNameReal(tmpstr, m->mixers[idx].dest + NUM_INPUTS + 1)); + write_int(fh, &m->mixers[idx], _secmixer, MAPSIZE(_secmixer)); + if(WRITE_FULL_MODEL || ! MIXER_APPLY_TRIM(&m->mixers[idx])) + fprintf(fh, "%s=%d\n", MIXER_USETRIM, MIXER_APPLY_TRIM(&m->mixers[idx]) ? 1 : 0); + if(WRITE_FULL_MODEL || MIXER_MUX(&m->mixers[idx])) + fprintf(fh, "%s=%s\n", MIXER_MUXTYPE, MIXER_MUXTYPE_VAL[MIXER_MUX(&m->mixers[idx])]); + if(WRITE_FULL_MODEL || CURVE_TYPE(&m->mixers[idx].curve)) { + fprintf(fh, "%s=%s\n", MIXER_CURVETYPE, MIXER_CURVETYPE_VAL[CURVE_TYPE(&m->mixers[idx].curve)]); + u8 num_points = CURVE_NumPoints(&m->mixers[idx].curve); + if (num_points > 0) { + fprintf(fh, "%s=", MIXER_CURVE_POINTS); + for (i = 0; i < num_points; i++) { + fprintf(fh, "%d", m->mixers[idx].curve.points[i]); + if (i != num_points - 1) + fprintf(fh, ","); + } + fprintf(fh, "\n"); + } + if (CURVE_SMOOTHING(&m->mixers[idx].curve)) + fprintf(fh, "%s=%d\n", MIXER_CURVE_SMOOTH, CURVE_SMOOTHING(&m->mixers[idx].curve) ? 1 : 0); + } + } + return changed; +} + +static void write_proto_opts(FILE *fh, struct Model *m) +{ + const char **opts = PROTOCOL_GetOptions(); + if (!opts || ! *opts) // bug fix: must check NULL ptr + return; + int idx = 0; + fprintf(fh, "[%s]\n", SECTION_PROTO_OPTS); + while(*opts) { + int start = exact_atoi(opts[1]); + int end = exact_atoi(opts[2]); + int is_num = ((start != 0 || end != 0) && (opts[3] == 0 || (opts[4] == 0 && exact_atoi(opts[3]) != 0))) ? 1 : 0; + if (is_num) { + fprintf(fh, "%s=%d\n",*opts, m->proto_opts[idx]); + } else { + fprintf(fh, "%s=%s\n",*opts, opts[m->proto_opts[idx]+1]); + } + opts++; + while(*opts) { + opts++; + } + opts++; + idx++; + } + fprintf(fh, "\n"); +} + +u8 CONFIG_WriteModel_old(u8 model_num) { + char file[20]; + FILE *fh; + u8 idx; + struct Model *m = &Model; + + + get_model_file(file, model_num); + fh = fopen(file, "w"); + if (! fh) { + printf("Couldn't open file: %s\n", file); + return 0; + } + CONFIG_EnableLanguage(0); + fprintf(fh, "%s=%s\n", MODEL_NAME, m->name); +#if HAS_PERMANENT_TIMER + write_int(fh, m, _secnone, MAPSIZE(_secnone)); +#endif + fprintf(fh, "%s=%s\n", MODEL_MIXERMODE, STDMIXER_ModeName(m->mixer_mode)); + if(m->icon[0] != 0) + fprintf(fh, "%s=%s\n", MODEL_ICON, m->icon + 9); + if(WRITE_FULL_MODEL || m->type != 0) + fprintf(fh, "%s=%s\n", MODEL_TYPE, MODEL_TYPE_VAL[m->type]); + fprintf(fh, "[%s]\n", SECTION_RADIO); + fprintf(fh, "%s=%s\n", RADIO_PROTOCOL, PROTOCOL_GetName(m->protocol)); + write_int(fh, m, _secradio, MAPSIZE(_secradio)); + fprintf(fh, "%s=%s\n", RADIO_TX_POWER, radio_tx_power_val(m->radio, m->tx_power)); + fprintf(fh, "\n"); + write_proto_opts(fh, m); + struct Limit default_limit; + memset(&default_limit, 0, sizeof(default_limit)); + MIXER_SetDefaultLimit(&default_limit); + for(idx = 0; idx < NUM_OUT_CHANNELS; idx++) { + if(!WRITE_FULL_MODEL + && memcmp(&m->limits[idx], &default_limit, sizeof(default_limit)) == 0 + && m->templates[idx] == 0) + { + if (write_mixer(fh, m, idx)) + fprintf(fh, "\n"); + continue; + } + fprintf(fh, "[%s%d]\n", SECTION_CHANNEL, idx+1); + if(WRITE_FULL_MODEL || (m->limits[idx].flags & CH_REVERSE)) + fprintf(fh, "%s=%d\n", CHAN_LIMIT_REVERSE, (m->limits[idx].flags & CH_REVERSE) ? 1 : 0); + write_int(fh, &m->limits[idx], _seclimit, MAPSIZE(_seclimit)); + if(WRITE_FULL_MODEL || (m->limits[idx].flags & CH_FAILSAFE_EN)) { + if(m->limits[idx].flags & CH_FAILSAFE_EN) { + fprintf(fh, "%s=%d\n", CHAN_LIMIT_FAILSAFE, m->limits[idx].failsafe); + } else { + fprintf(fh, "%s=Off\n", CHAN_LIMIT_FAILSAFE); + } + } + if(WRITE_FULL_MODEL || m->limits[idx].min != DEFAULT_SERVO_LIMIT) + fprintf(fh, "%s=%d\n", CHAN_LIMIT_MIN, -(int)m->limits[idx].min); + if(WRITE_FULL_MODEL || strcmp(m->limits[idx].displayformat, DEFAULT_DISPLAY_FORMAT) != 0) + fprintf(fh, "%s=%s\n", CHAN_DISPLAY_FORMAT, m->limits[idx].displayformat); + if(WRITE_FULL_MODEL || m->templates[idx] != 0) + fprintf(fh, "%s=%s\n", CHAN_TEMPLATE, CHAN_TEMPLATE_VAL[m->templates[idx]]); + write_mixer(fh, m, idx); + fprintf(fh, "\n"); + } + for(idx = 0; idx < NUM_VIRT_CHANNELS; idx++) { + if(WRITE_FULL_MODEL || m->templates[idx+NUM_OUT_CHANNELS] != 0 || m->virtname[idx][0]) { + fprintf(fh, "[%s%d]\n", SECTION_VIRTCHAN, idx+1); + if(m->virtname[idx][0]) + fprintf(fh, "%s=%s\n", VCHAN_NAME, m->virtname[idx]); + if(WRITE_FULL_MODEL || m->templates[idx+NUM_OUT_CHANNELS] != 0) + fprintf(fh, "%s=%s\n", VCHAN_TEMPLATE, VCHAN_TEMPLATE_VAL[m->templates[idx+NUM_OUT_CHANNELS]]); + } + if (write_mixer(fh, m, idx+NUM_OUT_CHANNELS)) + fprintf(fh, "\n"); + } + if (PPMin_Mode()) { + fprintf(fh, "[%s]\n", SECTION_PPMIN); + fprintf(fh, "%s=%s\n", PPMIN_MODE, PPMIN_MODE_VALUE[PPMin_Mode()]); + fprintf(fh, "%s=%d\n", PPMIN_NUM_CHANNELS, m->num_ppmin_channels); + if (PPMin_Mode() != PPM_IN_SOURCE) { + fprintf(fh, "%s=%s\n", PPMIN_SWITCH, INPUT_SourceNameReal(file, m->train_sw)); + } + write_int(fh, m, _secppm, MAPSIZE(_secppm)); + //fprintf(fh, "%s=%d\n", PPMIN_CENTERPW, m->ppmin_centerpw); + //fprintf(fh, "%s=%d\n", PPMIN_DELTAPW, m->ppmin_deltapw); + if (PPMin_Mode() != PPM_IN_SOURCE) { + int offset = (PPMin_Mode() == PPM_IN_TRAIN1) ? NUM_INPUTS + 1: 0; + for(idx = 0; idx < MAX_PPM_IN_CHANNELS; idx++) { + if (m->ppm_map[idx] == -1) + continue; + fprintf(fh, "%s%d=%s\n", PPMIN_MAP, idx + 1, INPUT_SourceNameReal(file, m->ppm_map[idx] + offset)); + } + } + fprintf(fh, "\n"); + } + for(idx = 0; idx < NUM_TRIMS; idx++) { + if (! WRITE_FULL_MODEL && m->trims[idx].src == 0) + continue; + fprintf(fh, "[%s%d]\n", SECTION_TRIM, idx+1); + fprintf(fh, "%s=%s\n", TRIM_SOURCE, + m->trims[idx].src >= 1 && m->trims[idx].src <= 4 + ? tx_stick_names[m->trims[idx].src-1] + : INPUT_SourceNameReal(file, m->trims[idx].src)); + write_int(fh, &m->trims[idx], _sectrim, MAPSIZE(_sectrim)); + if(WRITE_FULL_MODEL || m->trims[idx].sw) + fprintf(fh, "%s=%s\n", TRIM_SWITCH, INPUT_SourceNameAbbrevSwitchReal(file, m->trims[idx].sw)); + if(WRITE_FULL_MODEL || m->trims[idx].value[0] || m->trims[idx].value[1] || m->trims[idx].value[2] + || m->trims[idx].value[3] || m->trims[idx].value[4] || m->trims[idx].value[5]) + fprintf(fh, "%s=%d,%d,%d,%d,%d,%d\n", TRIM_VALUE, + m->trims[idx].value[0], m->trims[idx].value[1], m->trims[idx].value[2], + m->trims[idx].value[3], m->trims[idx].value[4], m->trims[idx].value[5]); + } + if (WRITE_FULL_MODEL || m->swash_type) { + fprintf(fh, "[%s]\n", SECTION_SWASH); + fprintf(fh, "%s=%s\n", SWASH_TYPE, MIXER_SwashType(m->swash_type)); + if (WRITE_FULL_MODEL || m->swash_invert & 0x01) + fprintf(fh, "%s=1\n", SWASH_ELE_INV); + if (WRITE_FULL_MODEL || m->swash_invert & 0x02) + fprintf(fh, "%s=1\n", SWASH_AIL_INV); + if (WRITE_FULL_MODEL || m->swash_invert & 0x04) + fprintf(fh, "%s=1\n", SWASH_COL_INV); + write_int(fh, m, _secswash, MAPSIZE(_secswash)); + } + for(idx = 0; idx < NUM_TIMERS; idx++) { + if (! WRITE_FULL_MODEL && m->timer[idx].src == 0 && m->timer[idx].type == TIMER_STOPWATCH) + continue; + fprintf(fh, "[%s%d]\n", SECTION_TIMER, idx+1); + if (WRITE_FULL_MODEL || m->timer[idx].type != TIMER_STOPWATCH) + fprintf(fh, "%s=%s\n", TIMER_TYPE, TIMER_TYPE_VAL[m->timer[idx].type]); + write_int(fh, &m->timer[idx], _sectimer, MAPSIZE(_sectimer)); + if (WRITE_FULL_MODEL || ((m->timer[idx].type == TIMER_COUNTDOWN || m->timer[idx].type == TIMER_COUNTDOWN_PROP) && m->timer[idx].timer)) + fprintf(fh, "%s=%d\n", TIMER_TIME, m->timer[idx].timer); + if (WRITE_FULL_MODEL || (m->timer[idx].val != 0 && m->timer[idx].type == TIMER_PERMANENT)) + fprintf(fh, "%s=%d\n", TIMER_VAL, m->timer[idx].val); + } + for(idx = 0; idx < TELEM_NUM_ALARMS; idx++) { + struct TelemetryAlarm *alarm = &m->alarms[idx]; + if (!WRITE_FULL_MODEL && !alarm->src) + continue; + fprintf(fh, "[%s%d]\n", SECTION_TELEMALARM, idx+1); + fprintf(fh, "%s=%s\n", TELEM_SRC, TELEMETRY_ShortName(file, alarm->src)); + if (WRITE_FULL_MODEL || alarm->above) + fprintf(fh, "%s=%d\n", TELEM_ABOVE, alarm->above); + fprintf(fh, "%s=%d\n", TELEM_VALUE, alarm->value); + fprintf(fh, "%s=%d\n", TELEM_THRESHOLD, alarm->threshold); + } +#if HAS_DATALOG + fprintf(fh, "[%s]\n", SECTION_DATALOG); + fprintf(fh, "%s=%s\n", DATALOG_SWITCH, INPUT_SourceNameReal(file, m->datalog.enable)); + fprintf(fh, "%s=%s\n", DATALOG_RATE, DATALOG_RateString(m->datalog.rate)); + for(idx = 0; idx < DLOG_LAST; idx++) { + if(m->datalog.source[DATALOG_BYTE(idx)] & (1 << DATALOG_POS(idx))) + fprintf(fh, "%s=%s\n", DATALOG_SOURCE, DATALOG_Source(file, idx)); + } +#endif //HAS_DATALOG + fprintf(fh, "[%s]\n", SECTION_SAFETY); + for(int i = 0; i < NUM_SOURCES + 1; i++) { + if (WRITE_FULL_MODEL || m->safety[i]) { + fprintf(fh, "%s=%s\n", i == 0 ? "Auto" : INPUT_SourceNameReal(file, i), SAFETY_VAL[m->safety[i]]); + } + } + fprintf(fh, "[%s]\n", SECTION_GUI); + for(idx = 0; idx < NUM_ELEMS; idx++) { + if (! ELEM_USED(Model.pagecfg2.elem[idx])) + break; + int src = Model.pagecfg2.elem[idx].src; + int x = ELEM_X(Model.pagecfg2.elem[idx]); + int y = ELEM_Y(Model.pagecfg2.elem[idx]); + int type = ELEM_TYPE(Model.pagecfg2.elem[idx]); + const char *elename = GetElemName(type); + switch(type) { + case ELEM_SMALLBOX: + case ELEM_BIGBOX: + fprintf(fh, "%s=%d,%d,%s\n", elename, x, y, GetBoxSourceReal(file, src)); + break; + case ELEM_BAR: + src += NUM_INPUTS; + fprintf(fh, "%s=%d,%d,%s\n", elename, x, y, INPUT_SourceNameReal(file, src)); + break; + case ELEM_TOGGLE: + fprintf(fh, "%s=%d,%d,%d,%d,%d,%s\n", elename, x, y, + Model.pagecfg2.elem[idx].extra[0], + Model.pagecfg2.elem[idx].extra[1], + INPUT_NumSwitchPos(src) == 2 ? 0 : Model.pagecfg2.elem[idx].extra[2], + INPUT_SourceNameAbbrevSwitchReal(file, src)); + break; + case ELEM_HTRIM: + case ELEM_VTRIM: + fprintf(fh, "%s=%d,%d,%d\n", elename, x, y, src); + break; + default: + fprintf(fh, "%s=%d,%d\n", elename, x, y); + break; + } + } + for(idx = 0; idx < NUM_QUICKPAGES; idx++) { + if (WRITE_FULL_MODEL || m->pagecfg2.quickpage[idx]) { + u8 val = m->pagecfg2.quickpage[idx]; + fprintf(fh, "%s%d=%s\n", GUI_QUICKPAGE, idx+1, PAGE_GetName(val)); + } + } +#if HAS_EXTENDED_AUDIO + fprintf(fh, "[%s]\n", SECTION_VOICE); + for (idx = 0; idx < NUM_SWITCHES; idx++) { + if (m->voice.switches[idx].music) + fprintf(fh, "%s=%d\n", INPUT_SourceName(file,idx + INP_HAS_CALIBRATION + 1), m->voice.switches[idx].music); + } +#if NUM_AUX_KNOBS + for (idx = 0; idx < NUM_AUX_KNOBS * 2; idx++) { + if (m->voice.aux[idx].music) { + if (idx % 2) + fprintf(fh, "%s_UP=%d\n", INPUT_SourceName(tempstring,(idx-1) / 2 + NUM_STICKS + 1), m->voice.aux[idx].music); + else + fprintf(fh, "%s_DOWN=%d\n", INPUT_SourceName(tempstring,idx / 2 + NUM_STICKS + 1), m->voice.aux[idx].music); + } + } +#endif + for (idx = 0; idx < NUM_TIMERS; idx++) { + if (m->voice.timer[idx].music) + fprintf(fh, "timer%d=%d\n", idx + 1, m->voice.timer[idx].music); + } + for (idx = 0; idx < TELEM_NUM_ALARMS; idx++) { + if (m->voice.telemetry[idx].music) + fprintf(fh, "telemalarm%d=%d\n", idx + 1, m->voice.telemetry[idx].music); + } + for (idx = 0; idx < (NUM_OUT_CHANNELS + NUM_VIRT_CHANNELS); idx++) { + if (m->voice.mixer[idx].music) + fprintf(fh, "%s=%d\n", INPUT_SourceNameReal(tempstring, idx + NUM_INPUTS + 1), m->voice.mixer[idx].music); + } +#endif + CONFIG_EnableLanguage(1); + fclose(fh); + return 1; +} + +static void clear_model(u8 full) +{ + u8 i; + if (full) { + memset(&Model, 0, sizeof(Model)); + } else { + memset(Model.mixers, 0, sizeof(Model.mixers)); + memset(Model.templates, 0, sizeof(Model.templates)); + memset(Model.trims, 0, sizeof(Model.trims)); + Model.swash_type = SWASH_TYPE_NONE; + Model.swash_invert = 0; + } + Model.mixer_mode = MIXER_ADVANCED; + Model.swashmix[0] = 60; + Model.swashmix[1] = 60; + Model.swashmix[2] = 60; + for(i = 0; i < NUM_MIXERS; i++) { + Model.mixers[i].scalar = 100; + MIXER_SET_APPLY_TRIM(&Model.mixers[i], 1); + } + for(i = 0; i < NUM_OUT_CHANNELS; i++) { + MIXER_SetDefaultLimit(&Model.limits[i]); + } + for (i = 0; i < NUM_TRIMS; i++) { + Model.trims[i].step = 1; + } + for (i = 0; i < MAX_PPM_IN_CHANNELS; i++) { + Model.ppm_map[i] = -1; + } + Model.ppmin_centerpw = 1500; + Model.ppmin_deltapw = 400; +} + +u8 CONFIG_ReadLayout_old(const char *filename) { + memset(&Model.pagecfg2, 0, sizeof(Model.pagecfg2)); + if (CONFIG_IniParse(filename, layout_ini_handler, &Model)) { + printf("Failed to parse Layout file: %s\n", filename); + return 0; + } + return 1; +} + +u8 CONFIG_ReadModel_old(const char* file) { + clear_model(1); + + auto_map = 0; + if (CONFIG_IniParse(file, ini_handler, &Model)) { + printf("Failed to parse Model file: %s\n", file); + } + if (! ELEM_USED(Model.pagecfg2.elem[0])) + CONFIG_ReadLayout_old("layout/default.ini"); + if(! PROTOCOL_HasPowerAmp(Model.protocol)) + Model.tx_power = TXPOWER_150mW; + MIXER_SetMixers(NULL, 0); + if(auto_map) + RemapChannelsForProtocol(EATRG0); + if(! Model.name[0]) + sprintf(Model.name, "Model%d", 1); + return 1; +} diff --git a/src/tests/models/280qav.ini b/src/tests/models/280qav.ini new file mode 100644 index 0000000000..060ff47855 --- /dev/null +++ b/src/tests/models/280qav.ini @@ -0,0 +1,100 @@ +name=280qav +mixermode=Advanced +type=multi +[radio] +protocol=DSMX +num_channels=7 +tx_power=150mW + +[channel1] +template=simple +[mixer] +src=THR +dest=Ch1 +curvetype=expo +points=0,0 + +[channel2] +reverse=1 +template=simple +[mixer] +src=AIL +dest=Ch2 +curvetype=expo +points=0,0 + +[channel3] +template=simple +[mixer] +src=ELE +dest=Ch3 +curvetype=expo +points=0,0 + +[channel4] +reverse=1 +template=simple +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=0,0 + +[channel5] +template=expo_dr +[mixer] +src=AIL +dest=Ch5 +scalar=125 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=SW A1 +scalar=50 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=SW A2 +scalar=0 +curvetype=fixed + +[channel6] +template=expo_dr +[mixer] +src=SW B1 +dest=Ch6 +scalar=125 +curvetype=fixed +[mixer] +src=SW B1 +dest=Ch6 +switch=SW B1 +scalar=50 +curvetype=fixed +[mixer] +src=SW B1 +dest=Ch6 +switch=SW B0 +scalar=0 +curvetype=fixed + +[safety] +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch1 +Small-box=2,31,Timer1 +Small-box=2,40,Timer2 +Model=75,20 +Battery=102,1 +Toggle=4,10,0,3,0,None +Toggle=13,10,0,5,0,None +Toggle=22,10,0,4,0,None +Toggle=31,10,0,0,0,None +Toggle=40,10,0,0,0,None +TxPower=102,7 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/4g6s.ini b/src/tests/models/4g6s.ini new file mode 100644 index 0000000000..e8207b802c --- /dev/null +++ b/src/tests/models/4g6s.ini @@ -0,0 +1,169 @@ +name=4G6 +mixermode=Advanced +icon=4G6S.BMP +[radio] +protocol=WK2601 +num_channels=7 +tx_power=30mW + +[protocol_opts] +Chan mode=6+1 +COL Inv=Normal +COL Limit=0 + +[channel1] +template=cyclic1 + +[channel2] +reverse=1 +template=cyclic2 + +[channel3] +template=complex +[mixer] +src=THR +dest=Ch3 +usetrim=0 +curvetype=3point +points=-100,48,100 +[mixer] +src=THR +dest=Ch3 +switch=FMODE1 +usetrim=0 +curvetype=3point +points=100,50,100 +[mixer] +src=THR +dest=Ch3 +switch=FMODE2 +usetrim=0 +curvetype=3point +points=100,75,100 +[mixer] +src=THR +dest=Ch3 +switch=GEAR1 +usetrim=0 +curvetype=3point +points=-100,-100,-100 + +[channel4] +reverse=1 +template=simple +[mixer] +src=RUD +dest=Ch4 +usetrim=0 +curvetype=expo +points=0,0 + +[channel6] +reverse=1 +template=cyclic3 + +[channel7] +template=expo_dr +[mixer] +src=Ch7 +dest=Ch7 +scalar=82 +usetrim=0 +curvetype=fixed +[mixer] +src=Ch7 +dest=Ch7 +switch=FMODE1 +scalar=82 +usetrim=0 +curvetype=fixed +[mixer] +src=Ch7 +dest=Ch7 +switch=FMODE2 +scalar=82 +usetrim=0 +curvetype=fixed + +[virtchan1] +template=expo_dr +[mixer] +src=AIL +dest=Virt1 +usetrim=0 +curvetype=expo +points=40,40 + +[virtchan2] +template=expo_dr +[mixer] +src=ELE +dest=Virt2 +usetrim=0 +curvetype=expo +points=40,40 + +[virtchan3] +template=expo_dr +[mixer] +src=THR +dest=Virt3 +usetrim=0 +curvetype=3point +points=-25,0,100 +[mixer] +src=THR +dest=Virt3 +switch=FMODE1 +usetrim=0 +[mixer] +src=THR +dest=Virt3 +switch=FMODE2 +usetrim=0 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +value=-100 +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[swash] +type=120 +ail_inv=1 +[timer2] +type=countdown +time=10 +[safety] +Auto=min +Ch3=min +[gui-qvga] +trim=4in +barsize=half +box1=Ch3 +box2=Timer1 +box3=Timer2 +bar1=Ch1 +bar2=Ch2 +bar3=Ch3 +bar4=Ch4 +toggle1=ELE DR +tglico1=0,1,0 +toggle2=AIL DR +tglico2=0,0,0 +toggle3=RUD DR +tglico3=0,2,0 +toggle4=GEAR +tglico4=0,4,0 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/apm.ini b/src/tests/models/apm.ini new file mode 100644 index 0000000000..773e57fadc --- /dev/null +++ b/src/tests/models/apm.ini @@ -0,0 +1,185 @@ +name=APM +mixermode=Advanced +icon=V212.BMP +type=plane +[radio] +protocol=DSM2 +num_channels=8 +fixed_id=636699 +tx_power=100mW + +[protocol_opts] +Telemetry=Off + +[channel1] +max=100 +min=-100 +template=complex +[mixer] +src=THR +dest=Ch1 +switch=RUD DR1 +[mixer] +src=AUX4 +dest=Ch1 +switch=RUD DR0 +scalar=-100 +usetrim=0 +curvetype=fixed + +[channel2] +reverse=1 +template=simple +[mixer] +src=AIL +dest=Ch2 + +[channel3] +reverse=1 +template=simple +[mixer] +src=ELE +dest=Ch3 + +[channel4] +reverse=1 +template=complex +[mixer] +src=RUD +dest=Ch4 +switch=RUD DR1 + +[channel5] +max=100 +min=-100 +template=complex +[mixer] +src=AUX5 +dest=Ch5 +switch=FMODE0 +scalar=-125 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=FMODE1 +scalar=-40 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=FMODE2 +scalar=-20 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=GEAR1 +scalar=10 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=MIX1 +scalar=40 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=MIX2 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=RUD DR0 +scalar=-100 +usetrim=0 +curvetype=fixed + +[channel6] +max=100 +min=-100 +template=complex +[mixer] +src=AUX5 +dest=Ch6 +usetrim=0 +curvetype=expo +points=0,0 + +[channel7] +max=100 +min=-100 +template=complex +[mixer] +src=ELE DR0 +dest=Ch7 +switch=ELE DR0 +scalar=-100 +usetrim=0 +[mixer] +src=AIL +dest=Ch7 +switch=ELE DR1 +usetrim=0 +curvetype=fixed + +[channel8] +max=100 +min=-100 +template=complex +[mixer] +src=AUX4 +dest=Ch8 +usetrim=0 +curvetype=expo +points=0,0 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +type=countdown +src=Ch1 +resetsrc=AIL DR1 +time=420 +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch1 +Small-box=2,31,Timer1 +Model=75,20 +Battery=102,1 +Toggle=42,10,72,0,0,RUD DR +Toggle=12,10,0,68,0,ELE DR +Toggle=2,10,0,193,194,FMODE +Toggle=32,10,0,196,197,MIX +Toggle=22,10,0,71,0,GEAR +TxPower=102,7 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/ardrone2.ini b/src/tests/models/ardrone2.ini new file mode 100644 index 0000000000..e65157d97d --- /dev/null +++ b/src/tests/models/ardrone2.ini @@ -0,0 +1,108 @@ +name=ArDrone2 +mixermode=Advanced +icon=DRONE2-2.BMP +type=plane +[radio] +protocol=DSM2 +num_channels=7 +fixed_id=123456 +tx_power=150mW + +[protocol_opts] +Telemetry=Off + +[channel1] +template=simple +[mixer] +src=THR +dest=Ch1 + +[channel2] +reverse=1 +template=simple +[mixer] +src=AIL +dest=Ch2 +scalar=45 +curvetype=expo +points=0,0 + +[channel3] +reverse=1 +template=simple +[mixer] +src=ELE +dest=Ch3 +scalar=45 +curvetype=expo +points=0,0 + +[channel4] +reverse=1 +template=simple +[mixer] +src=RUD +dest=Ch4 + +[channel5] +reverse=1 +template=simple +[mixer] +src=GEAR0 +dest=Ch5 +curvetype=min/max +points=0 + +[virtchan1] +name=Virt1 +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[trim5] +src=GEAR0 +pos=None +neg=None +switch=GEAR +[trim6] +src=MIX0 +pos=None +neg=None +[timer1] +type=countdown +src=GEAR1 +time=600 +[timer2] +type=stop-prop +src=THR +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-320x240] +V-trim=131,75,1 +H-trim=6,220,3 +V-trim=181,75,2 +H-trim=191,220,4 +Big-box=9,90,Timer1 +Small-box=9,150,Timer2 +Bargraph=205,150,Ch1 +Bargraph=235,150,Ch2 +Bargraph=265,150,Ch3 +Bargraph=295,150,Ch4 +Model=206,40 +Toggle=144,44,68,5,0,GEAR +Big-box=9,37,Ch1 \ No newline at end of file diff --git a/src/tests/models/bixler2.ini b/src/tests/models/bixler2.ini new file mode 100644 index 0000000000..55d514e79f --- /dev/null +++ b/src/tests/models/bixler2.ini @@ -0,0 +1,241 @@ +name=Bixler 2 +mixermode=Advanced +icon=BIXLER2.BMP +type=plane +[radio] +protocol=DEVO +num_channels=10 +fixed_id=870249 +tx_power=150mW + +[protocol_opts] +Telemetry=Off + +[channel1] +subtrim=-165 +template=complex +[mixer] +src=ELE +dest=Ch1 +switch=FMODE0 +scalar=80 +curvetype=expo +points=20,20 +[mixer] +src=ELE +dest=Ch1 +switch=FMODE1 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch1 +switch=MIX1 +scalar=20 +muxtype=add +curvetype=fixed +[mixer] +src=AIL +dest=Ch1 +switch=MIX2 +scalar=20 +muxtype=add +curvetype=fixed +[mixer] +src=ELE +dest=Ch1 +switch=FMODE2 +curvetype=expo +points=20,20 +[mixer] +src=ELE +dest=Ch1 +switch=FMODE2 +curvetype=expo +points=20,20 + +[channel2] +template=complex +[mixer] +src=AIL +dest=Ch2 +switch=FMODE0 +scalar=80 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE1 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE2 +curvetype=expo +points=20,20 + +[channel3] +safetysw=RUD DR0 +failsafe=-125 +safetyval=-150 +template=simple +[mixer] +src=THR +dest=Ch3 + +[channel4] +template=complex +[mixer] +src=RUD +dest=Ch4 +switch=FMODE0 +scalar=80 +curvetype=expo +points=20,20 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE1 +curvetype=expo +points=20,20 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE2 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch4 +switch=GEAR1 +curvetype=expo +points=20,20 + +[channel5] +template=complex +[mixer] +src=AIL +dest=Ch5 +switch=FMODE0 +scalar=80 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch5 +switch=FMODE1 +usetrim=0 +curvetype=expo +points=20,20 +[mixer] +src=AIL +dest=Ch5 +switch=FMODE2 +usetrim=0 +curvetype=expo +points=20,20 + +[channel6] +template=complex +[mixer] +src=ELE +dest=Ch6 +switch=MIX0 +scalar=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch6 +switch=MIX1 +scalar=40 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch6 +switch=MIX2 +scalar=60 +usetrim=0 +curvetype=fixed +[mixer] +src=!AIL +dest=Ch6 +switch=FMODE2 +usetrim=0 + +[channel7] +template=complex +[mixer] +src=MIX0 +dest=Ch7 +switch=MIX0 +scalar=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch7 +switch=MIX1 +scalar=-40 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch7 +switch=MIX2 +scalar=-60 +usetrim=0 +curvetype=fixed +[mixer] +src=!AIL +dest=Ch7 +switch=FMODE2 +usetrim=0 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +step=10 +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +step=10 +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +step=10 +[timer1] +type=countdown +src=Ch3 +resetsrc=AIL DR1 +time=630 +[timer2] +type=permanent +src=Ch3 +val=2709794 +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch3 +Small-box=2,31,Timer1 +Small-box=2,39,Timer2 +Model=75,20 +Toggle=2,11,0,193,194,FMODE +Toggle=23,11,0,196,197,MIX +Toggle=42,11,72,0,0,RUD DR +quickpage1=Mixer \ No newline at end of file diff --git a/src/tests/models/blade130x.ini b/src/tests/models/blade130x.ini new file mode 100644 index 0000000000..d4968f48a5 --- /dev/null +++ b/src/tests/models/blade130x.ini @@ -0,0 +1,198 @@ +name=Blade130X +mixermode=Advanced +icon=HELI.BMP +[radio] +protocol=DSMX +num_channels=7 +tx_power=100mW + +[protocol_opts] +Telemetry=Off + +[channel1] +safetysw=RUD DR1 +safetyval=-100 +template=complex +[mixer] +src=THR +dest=Ch1 +curvetype=7point +points=-100,-20,22,41,48,50,50 +[mixer] +src=THR +dest=Ch1 +switch=FMODE1 +curvetype=7point +points=100,87,73,60,73,87,100 +[mixer] +src=THR +dest=Ch1 +switch=FMODE2 +curvetype=fixed + +[channel2] +template=expo_dr +[mixer] +src=AIL +dest=Ch2 +curvetype=expo +points=30,30 +[mixer] +src=AIL +dest=Ch2 +switch=AIL DR1 +scalar=125 +curvetype=expo +points=0,0 + +[channel3] +template=expo_dr +[mixer] +src=ELE +dest=Ch3 +curvetype=expo +points=30,30 +[mixer] +src=ELE +dest=Ch3 +switch=ELE DR1 +scalar=125 +curvetype=expo +points=0,0 + +[channel4] +template=simple +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=-6,-6 + +[channel6] +template=complex +[mixer] +src=THR +dest=Ch6 +usetrim=0 +curvetype=7point +points=-40,-26,-13,0,33,66,100 +[mixer] +src=THR +dest=Ch6 +switch=FMODE1 +usetrim=0 +curvetype=7point +points=-100,-66,-33,0,33,66,100 +[mixer] +src=THR +dest=Ch6 +switch=FMODE2 +usetrim=0 +curvetype=7point +points=-100,-66,-33,0,33,66,100 +[mixer] +src=AIL +dest=Ch6 +switch=RUD DR1 +scalar=0 +usetrim=0 +curvetype=fixed + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +type=countdown +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-480x272] +V-trim=213,91,1 +H-trim=86,236,3 +V-trim=263,91,2 +H-trim=271,236,4 +Big-box=89,56,Ch1 +Big-box=89,106,Timer1 +Small-box=89,166,Timer2 +Small-box=89,197,Clock +Bargraph=285,166,Ch1 +Bargraph=298,166,Ch2 +Bargraph=312,166,Ch3 +Bargraph=326,166,Ch4 +Bargraph=340,166,Ch5 +Bargraph=354,166,Ch6 +Bargraph=368,166,Ch7 +Bargraph=382,166,Ch8 +Toggle=210,54,1,64,128,FMODE +Toggle=248,54,2,65,129,MIX +Toggle=227,92,8,71,0,GEAR +Toggle=227,131,5,132,68,ELE DR +Toggle=227,169,4,131,67,AIL DR +Toggle=227,208,3,130,66,RUD DR +Model=290,56 + +[gui-320x240] +V-trim=129,75,1 +H-trim=4,220,3 +V-trim=181,75,2 +H-trim=191,220,4 +Big-box=8,40,Ch1 +Small-box=8,95,Timer1 +Small-box=8,133,Timer2 +Small-box=8,172,Timer3 +Bargraph=200,150,Ch1 +Bargraph=214,150,Ch2 +Bargraph=228,150,Ch3 +Bargraph=242,150,Ch4 +Bargraph=256,150,Ch5 +Bargraph=270,150,Ch6 +Bargraph=284,150,Ch7 +Bargraph=298,150,Ch8 +Toggle=144,36,1,64,128,FMODE +Toggle=144,69,2,65,129,MIX +Toggle=144,102,5,68,0,ELE DR +Toggle=144,135,4,67,0,AIL DR +Toggle=144,168,3,66,0,RUD DR +Toggle=144,201,8,71,0,GEAR +Model=207,40 + +[gui-128x64] +V-trim=55,10,1 +H-trim=1,59,3 +V-trim=69,10,2 +H-trim=78,59,4 +Big-box=2,12,Ch1 +Small-box=2,28,Timer1 +Small-box=2,38,Timer2 +Small-box=2,48,Timer3 +Bargraph=79,30,Ch1 +Bargraph=85,30,Ch2 +Bargraph=91,30,Ch3 +Bargraph=97,30,Ch4 +Bargraph=103,30,Ch5 +Bargraph=109,30,Ch6 +Bargraph=115,30,Ch7 +Bargraph=121,30,Ch8 +Toggle=75,13,1,64,128,FMODE +Toggle=84,13,2,65,129,MIX +Toggle=93,13,0,5,0,ELE DR +Toggle=102,13,0,4,0,AIL DR +Toggle=111,13,0,8,0,GEAR +Toggle=120,13,0,3,0,RUD DR +Battery=102,1 +TxPower=75,1 \ No newline at end of file diff --git a/src/tests/models/deltaray.ini b/src/tests/models/deltaray.ini new file mode 100644 index 0000000000..67fe54b38b --- /dev/null +++ b/src/tests/models/deltaray.ini @@ -0,0 +1,116 @@ +name=DeltaRay 1 +mixermode=Advanced +icon=DELTARAY.BMP +type=plane +[radio] +protocol=DSM2 +num_channels=7 +tx_power=150mW + +[protocol_opts] +Telemetry=Off + +[channel1] +template=simple +[mixer] +src=THR +dest=Ch1 + +[channel2] +template=simple +[mixer] +src=AIL +dest=Ch2 +curvetype=expo +points=0,0 + +[channel3] +template=simple +[mixer] +src=ELE +dest=Ch3 +curvetype=expo +points=0,0 + +[channel4] +template=simple +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=40,40 + +[channel5] +max=100 +min=-100 +template=expo_dr +[mixer] +src=FMODE0 +dest=Ch5 +curvetype=fixed +[mixer] +src=FMODE0 +dest=Ch5 +switch=FMODE1 +scalar=0 +curvetype=fixed +[mixer] +src=FMODE0 +dest=Ch5 +switch=FMODE2 +scalar=-100 +curvetype=fixed + +[channel6] +reverse=1 +template=expo_dr +[mixer] +src=RUD DR0 +dest=Ch6 +curvetype=fixed +[mixer] +src=RUD DR0 +dest=Ch6 +switch=RUD DR1 +scalar=-100 +curvetype=fixed + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +value=-18 +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +src=THR +[timer2] +type=countdown +src=THR +time=585 +[safety] +Ch1=min +[gui-qvga] +trim=4in +barsize=half +box1=Timer1 +box2=Timer2 +box3=Timer2 +bar1=Ch1 +bar2=Ch2 +bar3=Ch3 +bar4=Ch4 +toggle1=FMODE +tglico1=3,1,2 +toggle2=RUD DR +tglico2=3,2,0 \ No newline at end of file diff --git a/src/tests/models/fx071.ini b/src/tests/models/fx071.ini new file mode 100644 index 0000000000..d3d68a35f6 --- /dev/null +++ b/src/tests/models/fx071.ini @@ -0,0 +1,219 @@ +name=FX071-Kiwi.Craig +mixermode=Advanced +icon=FX071.BMP +[radio] +protocol=KNFX +num_channels=10 +fixed_id=123456 +tx_power=100mW + +[protocol_opts] +Re-bind=No +1Mbps=No + +[channel1] +safetysw=RUD DR1 +safetyval=-100 +scalar-=100 +failsafe=-100 +template=simple +[mixer] +src=THR +dest=Ch1 +curvetype=5point +points=-100,-50,0,50,100 +smooth=1 + +[channel2] +scalar-=100 +template=complex +[mixer] +src=AIL +dest=Ch2 +scalar=30 +curvetype=expo +points=10,10 +[mixer] +src=AIL +dest=Ch2 +switch=MIX0 +scalar=5 +muxtype=add +curvetype=expo +points=0,0 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE1 +scalar=55 +curvetype=expo +points=15,15 +[mixer] +src=AIL +dest=Ch2 +switch=MIX0 +scalar=5 +muxtype=add +curvetype=expo +points=0,0 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE2 +scalar=70 +curvetype=expo +points=30,30 +[mixer] +src=AIL +dest=Ch2 +switch=MIX0 +scalar=10 +muxtype=add +curvetype=expo +points=0,0 + +[channel3] +scalar-=100 +template=complex +[mixer] +src=ELE +dest=Ch3 +scalar=30 +curvetype=expo +points=10,10 +[mixer] +src=ELE +dest=Ch3 +switch=MIX0 +scalar=5 +muxtype=add +curvetype=expo +points=0,0 +[mixer] +src=ELE +dest=Ch3 +switch=FMODE1 +scalar=55 +curvetype=expo +points=15,15 +[mixer] +src=ELE +dest=Ch3 +switch=MIX0 +scalar=5 +muxtype=add +curvetype=expo +points=0,0 +[mixer] +src=ELE +dest=Ch3 +switch=FMODE2 +scalar=70 +curvetype=expo +points=30,30 +[mixer] +src=ELE +dest=Ch3 +switch=MIX0 +scalar=10 +muxtype=add +curvetype=expo +points=0,0 + +[channel4] +safetysw=RUD DR1 +safetyval=-100 +failsafe=-100 +template=complex +[mixer] +src=RUD +dest=Ch4 +switch=FMODE0 +scalar=80 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE1 +curvetype=expo +points=10,10 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE2 +scalar=120 +curvetype=expo +points=20,20 + +[channel5] +template=simple +[mixer] +src=GEAR0 +dest=Ch5 +curvetype=expo +points=0,0 + +[channel6] +template=expo_dr +[mixer] +src=RUD DR1 +dest=Ch6 +curvetype=min/max +points=0 + +[channel8] +template=simple +[mixer] +src=MIX1 +dest=Ch8 +curvetype=expo +points=0,0 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +step=2 +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +step=2 +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +step=2 +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +step=2 +[timer1] +type=countdown +src=THR +resetsrc=AIL DR1 +time=390 +[timer2] +type=countdown +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch1 +Small-box=2,31,Timer1 +Small-box=2,40,None +Model=75,20 +Battery=102,1 +Toggle=4,10,9,72,0,RUD DR +Toggle=13,10,8,71,0,MIX +Toggle=22,10,2,65,129,FMODE +Toggle=31,10,6,69,0,GEAR +Toggle=40,10,0,0,0,None +TxPower=102,7 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/geniuscp.ini b/src/tests/models/geniuscp.ini new file mode 100644 index 0000000000..72e6d85caa --- /dev/null +++ b/src/tests/models/geniuscp.ini @@ -0,0 +1,149 @@ +name=Genius CP V2 +mixermode=Standard +[radio] +protocol=DEVO +num_channels=7 +tx_power=150mW + +[protocol_opts] +Telemetry=On + +[channel1] +template=cyclic2 + +[channel2] +template=cyclic1 + +[channel3] +safetysw=!HOLD0 +failsafe=-125 +safetyval=-110 +template=complex +[mixer] +src=THR +dest=Ch3 +curvetype=9point +points=-100,-50,-4,23,40,58,74,87,100 +[mixer] +src=THR +dest=Ch3 +switch=FMODE1 +curvetype=9point +points=100,84,69,58,50,58,69,84,100 + +[channel4] +template=expo_dr +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=0,0 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE1 +curvetype=expo +points=0,0 + +[channel6] +template=cyclic3 + +[channel7] +template=expo_dr +[mixer] +src=FMODE0 +dest=Ch7 +scalar=50 +curvetype=fixed +[mixer] +src=FMODE0 +dest=Ch7 +switch=FMODE1 +scalar=0 +curvetype=fixed + +[virtchan1] +template=expo_dr +[mixer] +src=AIL +dest=Virt1 +scalar=90 +curvetype=expo +points=0,0 +[mixer] +src=AIL +dest=Virt1 +switch=FMODE1 +curvetype=expo +points=0,0 + +[virtchan2] +template=expo_dr +[mixer] +src=ELE +dest=Virt2 +scalar=90 +curvetype=expo +points=0,0 +[mixer] +src=ELE +dest=Virt2 +switch=FMODE1 +curvetype=expo +points=0,0 + +[virtchan3] +template=complex +[mixer] +src=THR +dest=Virt3 +curvetype=9point +points=-20,-10,0,10,20,29,38,47,56 +[mixer] +src=THR +dest=Virt3 +switch=FMODE1 +curvetype=9point +points=-60,-45,-30,-15,0,15,30,45,60 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +type=countdown +src=Ch3 +time=180 +[timer2] +src=Ch3 +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch3 +Small-box=2,31,Timer1 +Small-box=2,39,Timer2 +Model=75,20 +Battery=102,1 +Toggle=4,10,0,3,0,None +Toggle=13,10,0,5,0,None +Toggle=22,10,0,4,0,None +Toggle=31,10,0,0,0,None +Toggle=40,10,0,0,0,None +TxPower=102,7 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/nazath.ini b/src/tests/models/nazath.ini new file mode 100644 index 0000000000..4424cd4098 --- /dev/null +++ b/src/tests/models/nazath.ini @@ -0,0 +1,135 @@ +name=Naza TH +mixermode=Advanced +icon=HUBSANX4.BMP +[radio] +protocol=DEVO +num_channels=10 +fixed_id=611642 +tx_power=150mW + +[protocol_opts] +Telemetry=Off + +[channel1] +template=simple +[mixer] +src=ELE +dest=Ch1 +curvetype=expo +points=0,0 + +[channel2] +template=simple +[mixer] +src=AIL +dest=Ch2 +curvetype=expo +points=0,0 + +[channel3] +template=simple +[mixer] +src=THR +dest=Ch3 +curvetype=expo +points=0,0 + +[channel4] +template=simple +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=0,0 + +[channel5] +template=expo_dr +[mixer] +src=MIX0 +dest=Ch5 +scalar=95 +curvetype=absval +points=0 +[mixer] +src=MIX0 +dest=Ch5 +switch=MIX1 +scalar=5 +curvetype=absval +points=0 +[mixer] +src=MIX0 +dest=Ch5 +switch=MIX2 +scalar=-80 +curvetype=absval +points=0 + +[channel6] +template=simple +[mixer] +src=PPM5 +dest=Ch6 +curvetype=expo +points=0,0 + +[channel7] +template=simple +[mixer] +src=PPM7 +dest=Ch7 +curvetype=expo +points=0,0 + +[channel8] +template=simple +[mixer] +src=PPM8 +dest=Ch8 +curvetype=expo +points=0,0 + +[ppm-in] +mode=extend +num_channels=8 +centerpw=1500 +deltapw=400 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +V-trim=65,10,2 +H-trim=74,59,4 +Small-box=2,22,Ch3 +Small-box=2,31,Timer1 +Small-box=2,39,Timer2 +Model=75,20 +Battery=102,1 +Toggle=4,10,0,3,0,RUD DR +Toggle=13,10,0,5,0,ELE DR +Toggle=22,10,0,4,0,AIL DR +Toggle=31,10,0,0,0,None +Toggle=40,10,0,0,0,None +TxPower=102,7 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/trex150dfc.ini b/src/tests/models/trex150dfc.ini new file mode 100644 index 0000000000..37842b8cb3 --- /dev/null +++ b/src/tests/models/trex150dfc.ini @@ -0,0 +1,242 @@ +name=TREX150DFC +mixermode=Advanced +icon=HELI.BMP +[radio] +protocol=DSMX +num_channels=7 +tx_power=100mW + +[protocol_opts] +Telemetry=Off + +[channel1] +safetysw=RUD DR1 +safetyval=-100 +template=complex +[mixer] +src=THR +dest=Ch1 +curvetype=7point +points=-100,-40,0,8,13,17,20 +[mixer] +src=THR +dest=Ch1 +switch=FMODE1 +curvetype=7point +points=40,36,33,28,33,36,40 +[mixer] +src=THR +dest=Ch1 +switch=FMODE2 +curvetype=7point +points=60,55,50,46,50,55,60 + +[channel2] +reverse=1 +template=expo_dr +[mixer] +src=AIL +dest=Ch2 +scalar=50 +curvetype=expo +points=30,30 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE1 +scalar=70 +curvetype=expo +points=30,30 +[mixer] +src=AIL +dest=Ch2 +switch=FMODE2 +scalar=125 + +[channel3] +reverse=1 +template=expo_dr +[mixer] +src=ELE +dest=Ch3 +scalar=50 +curvetype=expo +points=30,30 +[mixer] +src=ELE +dest=Ch3 +switch=FMODE1 +scalar=70 +curvetype=expo +points=30,30 +[mixer] +src=ELE +dest=Ch3 +switch=FMODE2 +scalar=125 + +[channel4] +reverse=1 +template=expo_dr +[mixer] +src=RUD +dest=Ch4 +curvetype=expo +points=15,15 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE1 +curvetype=expo +points=15,15 +[mixer] +src=RUD +dest=Ch4 +switch=FMODE2 + +[channel5] +template=complex +[mixer] +src=AIL +dest=Ch5 +switch=MIX0 +scalar=30 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=MIX1 +scalar=40 +curvetype=fixed +[mixer] +src=AIL +dest=Ch5 +switch=MIX2 +scalar=50 +curvetype=fixed + +[channel6] +reverse=1 +template=complex +[mixer] +src=THR +dest=Ch6 +scalar=60 +usetrim=0 +curvetype=7point +points=0,0,0,0,33,66,100 +[mixer] +src=THR +dest=Ch6 +switch=FMODE1 +scalar=70 +usetrim=0 +curvetype=7point +points=-30,-20,-10,0,33,66,100 +[mixer] +src=THR +dest=Ch6 +switch=FMODE2 +scalar=75 +usetrim=0 +curvetype=7point +points=-100,-66,-33,0,33,66,100 + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +type=countdown +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-480x272] +V-trim=213,91,1 +H-trim=86,236,3 +V-trim=263,91,2 +H-trim=271,236,4 +Big-box=89,56,Ch1 +Big-box=89,106,Timer1 +Small-box=89,166,Timer2 +Small-box=89,197,Clock +Bargraph=285,166,Ch1 +Bargraph=298,166,Ch2 +Bargraph=312,166,Ch3 +Bargraph=326,166,Ch4 +Bargraph=340,166,Ch5 +Bargraph=354,166,Ch6 +Bargraph=368,166,Ch7 +Bargraph=382,166,Ch8 +Toggle=210,54,1,64,128,FMODE +Toggle=248,54,2,65,129,MIX +Toggle=227,92,8,71,0,GEAR +Toggle=227,131,5,132,68,ELE DR +Toggle=227,169,4,131,67,AIL DR +Toggle=227,208,3,130,66,RUD DR +Model=290,56 + +[gui-320x240] +V-trim=129,75,1 +H-trim=4,220,3 +V-trim=181,75,2 +H-trim=191,220,4 +Big-box=8,40,Ch1 +Small-box=8,95,Timer1 +Small-box=8,133,Timer2 +Small-box=8,172,Timer3 +Bargraph=200,150,Ch1 +Bargraph=214,150,Ch2 +Bargraph=228,150,Ch3 +Bargraph=242,150,Ch4 +Bargraph=256,150,Ch5 +Bargraph=270,150,Ch6 +Bargraph=284,150,Ch7 +Bargraph=298,150,Ch8 +Toggle=144,36,1,64,128,FMODE +Toggle=144,69,2,65,129,MIX +Toggle=144,102,5,68,0,ELE DR +Toggle=144,135,4,67,0,AIL DR +Toggle=144,168,3,66,0,RUD DR +Toggle=144,201,8,71,0,GEAR +Model=207,40 + +[gui-128x64] +V-trim=55,10,1 +H-trim=1,59,3 +V-trim=69,10,2 +H-trim=78,59,4 +Big-box=2,12,Ch1 +Small-box=2,28,Timer1 +Small-box=2,38,Timer2 +Small-box=2,48,Timer3 +Bargraph=79,30,Ch1 +Bargraph=85,30,Ch2 +Bargraph=91,30,Ch3 +Bargraph=97,30,Ch4 +Bargraph=103,30,Ch5 +Bargraph=109,30,Ch6 +Bargraph=115,30,Ch7 +Bargraph=121,30,Ch8 +Toggle=75,13,1,64,128,FMODE +Toggle=84,13,2,65,129,MIX +Toggle=93,13,0,5,0,ELE DR +Toggle=102,13,0,4,0,AIL DR +Toggle=111,13,0,8,0,GEAR +Toggle=120,13,0,3,0,RUD DR +Battery=102,1 +TxPower=75,1 \ No newline at end of file diff --git a/src/tests/models/wltoys931.ini b/src/tests/models/wltoys931.ini new file mode 100644 index 0000000000..26520b706c --- /dev/null +++ b/src/tests/models/wltoys931.ini @@ -0,0 +1,206 @@ +name=V931 +mixermode=Advanced +icon=V931.BMP +type=plane +[radio] +protocol=KN +num_channels=11 +tx_power=100mW + +[protocol_opts] +Re-bind=No +1Mbps=Yes +Format=WLToys + +[channel1] +template=complex +[mixer] +src=THR +dest=Ch1 +switch=FMODE1 +scalar=95 +[mixer] +src=THR +dest=Ch1 +switch=!FMODE1 +usetrim=0 + +[channel2] +template=expo_dr +[mixer] +src=AIL +dest=Ch2 +scalar=60 +curvetype=expo +points=50,50 +[mixer] +src=AIL +dest=Ch2 +switch=MIX1 +scalar=80 +curvetype=expo +points=25,25 +[mixer] +src=AIL +dest=Ch2 +switch=MIX2 +curvetype=expo +points=0,0 + +[channel3] +template=expo_dr +[mixer] +src=ELE +dest=Ch3 +scalar=60 +curvetype=expo +points=50,50 +[mixer] +src=ELE +dest=Ch3 +switch=MIX1 +scalar=80 +curvetype=expo +points=25,25 +[mixer] +src=ELE +dest=Ch3 +switch=MIX2 +curvetype=expo +points=0,0 + +[channel4] +template=simple +[mixer] +src=RUD +dest=Ch4 + +[channel5] +template=simple +[mixer] +src=!AIL DR0 +dest=Ch5 +curvetype=min/max +points=0 + +[channel6] +template=simple +[mixer] +src=RUD DR1 +dest=Ch6 +curvetype=min/max +points=0 + +[channel7] +template=complex +[mixer] +src=FMODE0 +dest=Ch7 +switch=FMODE0 +scalar=-100 +usetrim=0 +curvetype=fixed +[mixer] +src=AIL +dest=Ch7 +switch=!FMODE0 +usetrim=0 +curvetype=fixed + +[channel8] +template=simple +[mixer] +src=!GEAR0 +dest=Ch8 +curvetype=min/max +points=0 + +[channel9] +template=simple + +[channel10] +template=simple + +[channel11] +template=simple + +[virtchan1] +template=simple +[mixer] +src=Ch1 +dest=Virt1 +scalar=50 +offset=50 + +[virtchan2] +template=complex +[mixer] +src=THR +dest=Virt2 +curvetype=expo +points=0,0 +[mixer] +src=THR +dest=Virt2 +switch=RUD DR1 +scalar=-100 +curvetype=fixed + +[trim1] +src=Ch9 +pos=TRIMLV+ +neg=TRIMLV- +step=10 +switch=GEAR +value=52,-18,0 +[trim2] +src=Ch11 +pos=TRIMRV+ +neg=TRIMRV- +step=10 +switch=GEAR +value=26,0,0 +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +switch=GEAR +[trim4] +src=Ch10 +pos=TRIMRH+ +neg=TRIMRH- +step=10 +switch=GEAR +value=33,0,0 +[timer1] +src=Virt2 +[timer2] +type=permanent +src=Virt2 +val=1733598 +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-320x240] +V-trim=133,75,1 +H-trim=6,220,3 +V-trim=183,75,2 +H-trim=191,220,4 +Big-box=9,40,Ch1 +Big-box=9,90,Timer1 +Small-box=9,140,Timer2 +Bargraph=205,150,Ch2 +Bargraph=235,150,Ch3 +Bargraph=265,150,Ch1 +Bargraph=295,150,Ch4 +Model=206,40 +Toggle=130,38,1,64,128,None +Toggle=168,38,2,65,129,None +Toggle=147,76,0,66,0,RUD DR +Toggle=147,113,0,67,0,AIL DR +Toggle=147,153,0,68,0,ELE DR +Toggle=147,192,8,71,0,None +Big-box=9,177,Virt1 +quickpage1=Telemetry monitor \ No newline at end of file diff --git a/src/tests/models/yacht.ini b/src/tests/models/yacht.ini new file mode 100644 index 0000000000..46d85c47c3 --- /dev/null +++ b/src/tests/models/yacht.ini @@ -0,0 +1,85 @@ +name=Joysway Orion +mixermode=Advanced +icon=YACHT.BMP +type=multi +[radio] +protocol=DSM2 +num_channels=2 +fixed_id=859231 +tx_power=100mW + +[protocol_opts] +Telemetry=On + +[channel1] +reverse=1 +template=complex +[mixer] +src=THR +dest=Ch1 +[mixer] +src=AIL +dest=Ch1 +switch=AIL DR1 +scalar=20 +usetrim=0 +muxtype=add +curvetype=fixed + +[channel2] +template=complex +[mixer] +src=RUD +dest=Ch2 +[mixer] +src=AIL +dest=Ch2 +usetrim=0 +muxtype=add + +[trim1] +src=LEFT_V +pos=TRIMLV+ +neg=TRIMLV- +[trim2] +src=RIGHT_V +pos=TRIMRV+ +neg=TRIMRV- +[trim3] +src=LEFT_H +pos=TRIMLH+ +neg=TRIMLH- +value=1,0,0 +[trim4] +src=RIGHT_H +pos=TRIMRH+ +neg=TRIMRH- +[timer1] +src=Ch3 +resetsrc=ELE DR1 +[timer2] +type=permanent +src=Ch3 +val=19187434 +[telemalarm1] +source=RxV +above=1 +value=500 +[datalog] +switch=None +rate=1 sec +[safety] +Auto=min +[gui-128x64] +V-trim=59,10,1 +H-trim=5,59,3 +Small-box=2,35,Timer1 +Small-box=2,45,Timer2 +Model=75,20 +Battery=102,1 +Toggle=22,10 +Switch=198,AIL DR1 +TxPower=102,7 +Big-box=2,21,Volt1 +quickpage1=Channel monitor +quickpage2=Telemetry monitor \ No newline at end of file diff --git a/src/tests/test_model.c b/src/tests/test_model.c index f5884c35db..f4754db55e 100644 --- a/src/tests/test_model.c +++ b/src/tests/test_model.c @@ -1,5 +1,65 @@ #include "CuTest.h" +extern u8 CONFIG_ReadModel_old(const char* file); +extern u8 CONFIG_WriteModel_old(u8 model_num); + +u8 CONFIG_ReadModel_new(const char* file) { + clear_model(1); + + auto_map = 0; + if (CONFIG_IniParse(file, ini_handler, &Model)) { + printf("Failed to parse Model file: %s\n", file); + } + if (! ELEM_USED(Model.pagecfg2.elem[0])) + CONFIG_ReadLayout("layout/default.ini"); + if(! PROTOCOL_HasPowerAmp(Model.protocol)) + Model.tx_power = TXPOWER_150mW; + MIXER_SetMixers(NULL, 0); + if(auto_map) + RemapChannelsForProtocol(EATRG0); + if(! Model.name[0]) + sprintf(Model.name, "Model%d", 1); + return 1; +} + +const char* const names[] = { +"tests/models/280qav.ini", +"tests/models/bixler2.ini", +"tests/models/geniuscp.ini", +"tests/models/yacht.ini", + +"tests/models/4g6s.ini", +"tests/models/blade130x.ini", +"tests/models/nazath.ini", + +"tests/models/apm.ini", +"tests/models/deltaray.ini", +"tests/models/trex150dfc.ini", + +"tests/models/ardrone2.ini", +"tests/models/fx071.ini", +"tests/models/wltoys931.ini", +}; + +void TestNewAndOld(CuTest *t) +{ + struct Model ValidateModel; + + for (unsigned i = 0; i < ARRAYSIZE(names); i++) { + const char *filename = names[i]; + printf("Test model: %s\n", filename); + CONFIG_ReadModel_old(filename); + memcpy(&ValidateModel, &Model, sizeof(Model)); + CONFIG_ReadModel_new(filename); + + CuAssertTrue(t, memcmp(&ValidateModel, &Model, sizeof(Model)) == 0); + + CONFIG_WriteModel(1); + CONFIG_ReadModel(1); + CuAssertTrue(t, memcmp(&ValidateModel, &Model, sizeof(Model)) == 0); + } +} + void TestModelLoadSave(CuTest *t) { struct Model ValidateModel;