From 0af34aa4f214164e2ee3ed4c721781c86f0d8873 Mon Sep 17 00:00:00 2001 From: Frankie Arzu <32604366+frankiearzu@users.noreply.github.com> Date: Fri, 8 Mar 2024 00:01:38 -0600 Subject: [PATCH] feat: SoarETX V2, support for F3J/F5J 4-servo wing templates (#126) --- .../TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml | 2243 ++++++++++++++++ .../TEMPLATES/4.SoarETX_v2/F3J_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3J_v2.yml | 2014 ++++++++++++++ .../TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt} | 0 .../TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml} | 109 +- .../TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt} | 0 .../TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml | 1177 ++++++++ .../TEMPLATES/4.SoarETX_v2/F3K_v2.txt} | 0 .../TEMPLATES/4.SoarETX_v2/F3K_v2.yml} | 135 +- .../TEMPLATES/4.SoarETX_v2/F5J_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F5J_v2.yml | 2382 +++++++++++++++++ .../c480x272/TEMPLATES/4.SoarETX_v2/about.txt | 4 + sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua | 4 +- sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua | 5 +- sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua | 4 +- sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua | 183 ++ sdcard/c480x272/WIDGETS/SoarETX/2/battery.lua | 35 + sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua | 225 ++ sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua | 351 +++ sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua | 1264 +++++++++ sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua | 417 +++ sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua | 586 ++++ sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua | 213 ++ sdcard/c480x272/WIDGETS/SoarETX/2/name.lua | 38 + sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua | 595 ++++ sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua | 214 ++ sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua | 359 +++ sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua | 382 +++ sdcard/c480x272/WIDGETS/SoarETX/main.lua | 38 +- .../c480x320/TEMPLATES/3.SoarETX/F3K RE.txt | 1 + .../c480x320/TEMPLATES/3.SoarETX/F3K RE.yml | 559 ++++ .../c480x320/TEMPLATES/3.SoarETX/F3K TRAD.txt | 1 + .../{SoarETX => 3.SoarETX}/F3K TRAD.yml | 0 .../c480x320/TEMPLATES/3.SoarETX/F3K-TRAD.yml | 1192 +++++++++ sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.txt | 2 + sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.yml | 1362 ++++++++++ .../{SoarETX => 3.SoarETX}/about.txt | 0 .../TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml | 2243 ++++++++++++++++ .../TEMPLATES/4.SoarETX_v2/F3J_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3J_v2.yml | 2014 ++++++++++++++ .../TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml | 579 ++++ .../TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml | 1177 ++++++++ .../TEMPLATES/4.SoarETX_v2/F3K_v2.txt | 2 + .../TEMPLATES/4.SoarETX_v2/F3K_v2.yml | 1355 ++++++++++ .../TEMPLATES/4.SoarETX_v2/F5J_v2.txt | 1 + .../TEMPLATES/4.SoarETX_v2/F5J_v2.yml | 2382 +++++++++++++++++ .../c480x320/TEMPLATES/4.SoarETX_v2/about.txt | 4 + sdcard/c480x320/WIDGETS/SoarETX/1/battery.lua | 45 +- sdcard/c480x320/WIDGETS/SoarETX/1/brkcrv.lua | 219 ++ sdcard/c480x320/WIDGETS/SoarETX/1/f3k.lua | 16 +- .../c480x320/WIDGETS/SoarETX/1/f3kfh_mx.lua | 159 ++ sdcard/c480x320/WIDGETS/SoarETX/1/graph.lua | 89 +- sdcard/c480x320/WIDGETS/SoarETX/1/wing2.lua | 53 +- sdcard/c480x320/WIDGETS/SoarETX/1/wing4.lua | 357 +++ sdcard/c480x320/WIDGETS/SoarETX/2/ailctr.lua | 184 ++ sdcard/c480x320/WIDGETS/SoarETX/2/battery.lua | 35 + sdcard/c480x320/WIDGETS/SoarETX/2/brkcrv.lua | 226 ++ sdcard/c480x320/WIDGETS/SoarETX/2/f3J.lua | 351 +++ sdcard/c480x320/WIDGETS/SoarETX/2/f3k.lua | 1265 +++++++++ sdcard/c480x320/WIDGETS/SoarETX/2/f5J.lua | 392 +++ sdcard/c480x320/WIDGETS/SoarETX/2/graph.lua | 586 ++++ sdcard/c480x320/WIDGETS/SoarETX/2/mixes.lua | 214 ++ sdcard/c480x320/WIDGETS/SoarETX/2/name.lua | 38 + sdcard/c480x320/WIDGETS/SoarETX/2/outputs.lua | 595 ++++ sdcard/c480x320/WIDGETS/SoarETX/2/switch.lua | 215 ++ sdcard/c480x320/WIDGETS/SoarETX/2/wing2.lua | 360 +++ sdcard/c480x320/WIDGETS/SoarETX/2/wing4.lua | 383 +++ sdcard/c480x320/WIDGETS/SoarETX/main.lua | 82 +- 72 files changed, 31553 insertions(+), 169 deletions(-) create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.txt create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.yml rename sdcard/{c480x320/TEMPLATES/SoarETX/F3K RE.txt => c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt} (100%) rename sdcard/{c480x320/TEMPLATES/SoarETX/F3K RE.yml => c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml} (80%) rename sdcard/{c480x320/TEMPLATES/SoarETX/F3K TRAD.txt => c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt} (100%) create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml rename sdcard/{c480x320/TEMPLATES/SoarETX/F3K.txt => c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.txt} (100%) rename sdcard/{c480x320/TEMPLATES/SoarETX/F3K.yml => c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.yml} (87%) create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.txt create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.yml create mode 100644 sdcard/c480x272/TEMPLATES/4.SoarETX_v2/about.txt create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/battery.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/name.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua create mode 100644 sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.txt create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.yml create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.txt rename sdcard/c480x320/TEMPLATES/{SoarETX => 3.SoarETX}/F3K TRAD.yml (100%) create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K-TRAD.yml create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.txt create mode 100644 sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.yml rename sdcard/c480x320/TEMPLATES/{SoarETX => 3.SoarETX}/about.txt (100%) create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.txt create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.yml create mode 100644 sdcard/c480x320/TEMPLATES/4.SoarETX_v2/about.txt create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/1/brkcrv.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/1/f3kfh_mx.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/1/wing4.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/ailctr.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/battery.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/brkcrv.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/f3J.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/f3k.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/f5J.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/graph.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/mixes.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/name.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/outputs.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/switch.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/wing2.lua create mode 100644 sdcard/c480x320/WIDGETS/SoarETX/2/wing4.lua diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt new file mode 100644 index 00000000..2f024356 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt @@ -0,0 +1 @@ +F3J Model (V-TAIL, 4 Servo Wings) \ No newline at end of file diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml new file mode 100644 index 00000000..b3f421f0 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml @@ -0,0 +1,2243 @@ +semver: 2.9.1 +header: + name: "F3J VT_v2" + modelId: + 0: + val: 2 + bitmap: "ehawk.bmp" + labels: "glider" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" + 1: + start: 0 + swtch: "L20" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 50 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 0 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 0 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 1 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 1 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilR" + - + weight: -100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L31" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 23 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 45 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: -139 + symetrical: 0 + revert: 1 + curve: 0 + name: "Elev" + 2: + min: 0 + max: -510 + ppmCenter: 0 + offset: -160 + symetrical: 0 + revert: 1 + curve: 1 + name: "LftAil" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 490 + max: 0 + ppmCenter: 0 + offset: -10 + symetrical: 0 + revert: 1 + curve: 2 + name: "RgtAil" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -43 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: -50 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 50 + 19: + val: 100 + 20: + val: -71 + 21: + val: -42 + 22: + val: -21 + 23: + val: -2 + 24: + val: 20 + 25: + val: 100 + 26: + val: 77 + 27: + val: 56 + 28: + val: 37 + 29: + val: 18 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 59: + val: 100 + 61: + val: 100 + 62: + val: -100 + 63: + val: 100 + 64: + val: 100 + 65: + val: 90 + 166: + val: -50 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VPOS + def: "gv(8),0" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_VEQUAL + def: "gv(8),2" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_EDGE + def: "!L20,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_OR + def: "!L5,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_STICKY + def: "L22,L24" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "L25,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L29" + delay: 0 + duration: 0 + 30: + func: FUNC_STICKY + def: "L29,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_AND + def: "L31,!L29" + andsw: "!L30" + delay: 30 + duration: 0 + 33: + func: FUNC_AND + def: "L10,L19" + andsw: "NONE" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 3: + swtch: "L2" + func: VARIO + def: "" + 4: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 5: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER2,10" + 6: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 10: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 12: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 16: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 20: + swtch: "L22" + func: PLAY_TRACK + def: "fm-lch,1x" + 21: + swtch: "L32" + func: PLAY_TRACK + def: "flapup,5" + 22: + swtch: "L34" + func: LOGS + def: "50" + 23: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 24: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 25: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -42 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 0 + 2: + val: 20 + 3: + val: 0 + 4: + val: 11 + 5: + val: 0 + 6: + val: 150 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 4 + 2: + value: -128 + mode: 4 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L25" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L27" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -74 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 64,0 + channelsStart: 0 + channelsCount: 8 + failsafeMode: CUSTOM + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + receiverTelemetryOff: 0 + receiverHigherChannels: 0 + optionValue: 0 +failsafeChannels: + 0: + val: 45 + 1: + val: 143 + 2: + val: 115 + 3: + val: -32 + 4: + val: 32 + 5: + val: 43 + 9: + val: -1 + 10: + val: 32 + 11: + val: 32 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 272 + id2: + instance: 26 + label: "VSpd" + subId: 0 + type: TYPE_CUSTOM + unit: 5 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + id1: + id: 61699 + id2: + instance: 26 + label: "A2" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 2: + id1: + id: 256 + id2: + instance: 26 + label: "Alt" + subId: 0 + type: TYPE_CUSTOM + unit: 9 + prec: 1 + autoOffset: 1 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 61697 + id2: + instance: 24 + label: "RSSI" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + id1: + id: 65534 + id2: + instance: 248 + label: "TRSS" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + id1: + id: 65533 + id2: + instance: 248 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + id1: + id: 61700 + id2: + instance: 24 + label: "RxBt" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x000000 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0x000000 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f3j" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F3J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F3J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.txt new file mode 100644 index 00000000..5c4ae4b3 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.txt @@ -0,0 +1 @@ +F3J Model (4 Servo Wings) \ No newline at end of file diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.yml new file mode 100644 index 00000000..1b24f8f5 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3J_v2.yml @@ -0,0 +1,2014 @@ +semver: 2.9.1 +header: + name: "F3J_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" + 1: + start: 0 + swtch: "L20" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L31" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 23 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 1 + name: "LftAil" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 2 + name: "RgtAil" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: -50 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 50 + 19: + val: 100 + 20: + val: -100 + 21: + val: -50 + 23: + val: 35 + 24: + val: 70 + 25: + val: -50 + 26: + val: -50 + 27: + val: -50 + 28: + val: -25 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 59: + val: 100 + 61: + val: 100 + 62: + val: -100 + 63: + val: 100 + 64: + val: 100 + 65: + val: 90 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VPOS + def: "gv(8),0" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_VEQUAL + def: "gv(8),2" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_EDGE + def: "!L20,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_OR + def: "!L5,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_STICKY + def: "L22,L24" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "L25,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L29" + delay: 0 + duration: 0 + 30: + func: FUNC_STICKY + def: "L29,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_AND + def: "L31,!L29" + andsw: "!L30" + delay: 30 + duration: 0 + 33: + func: FUNC_AND + def: "L10,L19" + andsw: "NONE" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 3: + swtch: "L2" + func: VARIO + def: "" + 4: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 5: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER2,10" + 6: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 10: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 12: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 16: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 20: + swtch: "L22" + func: PLAY_TRACK + def: "fm-lch,1x" + 21: + swtch: "L32" + func: PLAY_TRACK + def: "flapup,5" + 22: + swtch: "L34" + func: LOGS + def: "50" + 23: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 24: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 25: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 50 + 2: + val: 20 + 3: + val: 0 + 4: + val: 15 + 5: + val: -20 + 6: + val: 100 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 4 + 2: + value: 0 + mode: 4 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L25" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L27" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 2: + val: -438 + 3: + val: 435 + 4: + val: 1095 + 5: + val: 1014 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x000000 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0x000000 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f3j" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F3J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F3J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K RE.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt similarity index 100% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K RE.txt rename to sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K RE.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml similarity index 80% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K RE.yml rename to sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml index b74e2a79..575c9920 100644 --- a/sdcard/c480x320/TEMPLATES/SoarETX/F3K RE.yml +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml @@ -1,6 +1,8 @@ +semver: 2.9.1 header: - name: "F3K RE" + name: "F3K RE_v2" bitmap: "" + labels: "" timers: 0: start: 0 @@ -11,6 +13,8 @@ timers: minuteBeep: 0 persistent: 0 countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 name: "Flight" 1: start: 0 @@ -21,6 +25,8 @@ timers: minuteBeep: 0 persistent: 0 countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 name: "Window" telemetryProtocol: 0 thrTrim: 0 @@ -33,6 +39,10 @@ displayChecklist: 0 extendedLimits: 1 extendedTrims: 0 throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 beepANACenter: 0 mixData: - @@ -88,8 +98,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 0 srcRaw: Ail - carryTrim: 0 chn: 0 swtch: "NONE" flightModes: 000000000 @@ -99,8 +109,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 0 srcRaw: Ele - carryTrim: 0 chn: 1 swtch: "NONE" flightModes: 000000000 @@ -113,8 +123,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: S1 - carryTrim: 1 chn: 2 swtch: "NONE" flightModes: 000000000 @@ -213,14 +223,14 @@ logicalSw: delay: 0 duration: 0 17: - func: FUNC_AND - def: "FM2,L16" + func: FUNC_OR + def: "FM1,FM2" andsw: "NONE" delay: 0 duration: 0 18: - func: FUNC_OR - def: "FM1,L18" + func: FUNC_AND + def: "L18,L16" andsw: "L8" delay: 0 duration: 0 @@ -247,6 +257,14 @@ customFn: swtch: "L20" func: LOGS def: "100" + 4: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 5: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" flightModeData: 0: name: "Cruise" @@ -350,8 +368,12 @@ varioData: min: 0 max: 0 rssiSource: none +rfAlarms: + warning: 45 + critical: 42 thrTrimSw: 0 potsWarnMode: WARN_OFF +jitterFilter: GLOBAL failsafeChannels: 4: val: 1024 @@ -359,6 +381,13 @@ failsafeChannels: val: -1024 6: val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 inputNames: 0: val: "Rudd" @@ -384,6 +413,10 @@ screenData: type: String value: stringValue: "f3k" + 2: + type: String + value: + stringValue: "" options: 0: type: Bool @@ -416,11 +449,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K_RE" 1: widgetName: "SoarETX" widgetData: @@ -428,35 +465,47 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "f3kre_mx" - 5: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K_RE" + 3: widgetName: "SoarETX" widgetData: options: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "f3kre_sw" - 3: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3K_RE" + 5: widgetName: "SoarETX" widgetData: options: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "graph" + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K_RE" options: 0: type: Bool @@ -492,6 +541,10 @@ topbarData: type: String value: stringValue: "name" + 2: + type: String + value: + stringValue: "" 3: widgetName: "SoarETX" widgetData: @@ -504,5 +557,23 @@ topbarData: type: String value: stringValue: "battery" -view: 0 -modelRegistrationID: "" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K TRAD.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt similarity index 100% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K TRAD.txt rename to sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml new file mode 100644 index 00000000..2f0677dc --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml @@ -0,0 +1,1177 @@ +semver: 2.9.1 +header: + name: "F3K TRAD_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 0 + swtch: "L16" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "L15" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -GV5 + destCh: 1 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 3 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 29 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 29 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L25" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 10 + destCh: 30 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 011001111 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 30 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV6 + destCh: 30 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "SnpFlp" + - + weight: GV2 + destCh: 31 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Brake" + - + weight: GV2 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Offset" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Camber" + - + weight: 100 + destCh: 31 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L11" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 1 + name: "Left" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 2 + name: "Right" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: GV7 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: GV8 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Align" + offset: 0 + curve: + type: 3 + value: 7 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: S1 + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Dial" + offset: 0 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "Lft" + 1: + type: 0 + smooth: 1 + points: 0 + name: "Rgt" + 2: + type: 0 + smooth: 0 + points: -2 + name: "BrF" + 3: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 4: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 5: + type: 1 + smooth: 0 + points: -2 + name: "DB" + 6: + type: 1 + smooth: 0 + points: 5 + name: "Aln" + 31: + type: 0 + smooth: 0 + points: 0 + name: "Mem" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: 50 + 12: + val: 100 + 13: + val: -100 + 14: + val: -100 + 17: + val: -50 + 19: + val: 100 + 21: + val: 100 + 22: + val: -100 + 23: + val: 100 + 24: + val: 100 + 25: + val: 90 + 26: + val: -100 + 27: + val: -100 + 28: + val: -50 + 29: + val: -50 + 32: + val: 50 + 33: + val: 50 + 34: + val: 100 + 35: + val: 100 + 36: + val: -75 + 37: + val: -75 + 38: + val: -25 + 39: + val: -25 + 40: + val: 25 + 41: + val: 25 + 42: + val: 75 + 43: + val: 75 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + andsw: "L16" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SD2,NONE" + andsw: "L1" + delay: 0 + duration: 0 + 6: + func: FUNC_OR + def: "SF2,L9" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_AND + def: "L7,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 10: + func: FUNC_STICKY + def: "L11,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 11: + func: FUNC_STICKY + def: "L12,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 12: + func: FUNC_OR + def: "L11,L12" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_STICKY + def: "L15,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_STICKY + def: "L16,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 17: + func: FUNC_ADIFFEGREATER + def: "Ail,6" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_ADIFFEGREATER + def: "Ele,6" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_OR + def: "L18,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 20: + func: FUNC_STICKY + def: "FM1,L20" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_VPOS + def: "I3,90" + andsw: "!FM1" + delay: 0 + duration: 0 + 23: + func: FUNC_STICKY + def: "FM1,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_OR + def: "L24,L13" + andsw: "NONE" + delay: 0 + duration: 0 + 25: + func: FUNC_AND + def: "!FM1,L24" + andsw: "!L23" + delay: 30 + duration: 0 + 27: + func: FUNC_AND + def: "FM2,L16" + andsw: "NONE" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "FM1,L28" + andsw: "L8" + delay: 0 + duration: 0 + 29: + func: FUNC_AND + def: "!L29,L16" + andsw: "L8" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "L2" + func: VARIO + def: "" + 1: + swtch: "L5" + func: PLAY_VALUE + def: "TIMER2,10" + 2: + swtch: "L26" + func: PLAY_TRACK + def: "flapup,5" + 3: + swtch: "L29" + func: LOGS + def: "10" + 4: + swtch: "L30" + func: LOGS + def: "100" + 5: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 6: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" + 7: + swtch: "FM4" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 66 + 1: + val: 67 + 2: + val: 10 + 3: + val: 0 + 4: + val: 12 + 5: + val: 25 + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 0 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L7" + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + name: "Zoom" + swtch: "L21" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 8 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "Brk" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "Ele" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Exp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 3: + val: "Brk" + 4: + val: "CbPS" + 5: + val: "Cmb" + 6: + val: "Aln" + 7: + val: "Pokr" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "f3k" + 2: + type: String + value: + stringValue: "" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing2" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "ailctr" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K_TRAD" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 8 +modelRegistrationID: "-eC!U*U*" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.txt similarity index 100% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K.txt rename to sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.txt diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.yml similarity index 87% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K.yml rename to sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.yml index eaae3ba5..7f3ba037 100644 --- a/sdcard/c480x320/TEMPLATES/SoarETX/F3K.yml +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F3K_v2.yml @@ -1,6 +1,8 @@ +semver: 2.9.1 header: - name: "F3K" + name: "F3K_v2" bitmap: "" + labels: "" timers: 0: start: 0 @@ -11,6 +13,8 @@ timers: minuteBeep: 0 persistent: 0 countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 name: "Flight" 1: start: 0 @@ -21,6 +25,8 @@ timers: minuteBeep: 0 persistent: 0 countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 name: "Window" telemetryProtocol: 0 thrTrim: 0 @@ -33,6 +39,10 @@ displayChecklist: 0 extendedLimits: 1 extendedTrims: 0 throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 beepANACenter: 0 mixData: - @@ -520,8 +530,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 0 srcRaw: Rud - carryTrim: 0 chn: 0 swtch: "NONE" flightModes: 000000000 @@ -531,8 +541,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 0 srcRaw: Ele - carryTrim: 0 chn: 1 swtch: "NONE" flightModes: 000000000 @@ -545,8 +555,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 0 srcRaw: Ail - carryTrim: 0 chn: 2 swtch: "NONE" flightModes: 000000000 @@ -559,8 +569,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: Thr - carryTrim: 1 chn: 3 swtch: "NONE" flightModes: 000000000 @@ -570,8 +580,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: TrimThr - carryTrim: 1 chn: 4 swtch: "NONE" flightModes: 000000000 @@ -584,8 +594,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: MAX - carryTrim: 1 chn: 5 swtch: "NONE" flightModes: 000000000 @@ -595,8 +605,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: Thr - carryTrim: 1 chn: 6 swtch: "NONE" flightModes: 000000000 @@ -609,8 +619,8 @@ expoData: - mode: 3 scale: 0 + trimSource: 1 srcRaw: S1 - carryTrim: 1 chn: 7 swtch: "NONE" flightModes: 000000000 @@ -865,14 +875,14 @@ logicalSw: delay: 30 duration: 0 27: - func: FUNC_AND - def: "FM2,L16" + func: FUNC_OR + def: "FM1,FM2" andsw: "NONE" delay: 0 duration: 0 28: - func: FUNC_OR - def: "FM1,L28" + func: FUNC_AND + def: "L28,L16" andsw: "L8" delay: 0 duration: 0 @@ -903,6 +913,18 @@ customFn: swtch: "L30" func: LOGS def: "100" + 5: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 6: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" + 7: + swtch: "FM4" + func: PLAY_TRACK + def: "therml,1x" flightModeData: 0: trim: @@ -915,9 +937,9 @@ flightModeData: fadeOut: 0 gvars: 0: - val: 66 + val: 70 1: - val: 67 + val: 65 2: val: 10 3: @@ -941,7 +963,7 @@ flightModeData: value: -60 mode: 2 2: - value: 0 + value: -20 mode: 2 3: value: 0 @@ -1080,8 +1102,12 @@ varioData: min: 0 max: 0 rssiSource: none +rfAlarms: + warning: 45 + critical: 42 thrTrimSw: 0 potsWarnMode: WARN_OFF +jitterFilter: GLOBAL failsafeChannels: 4: val: 1024 @@ -1089,6 +1115,13 @@ failsafeChannels: val: -1024 6: val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 inputNames: 0: val: "Rudd" @@ -1124,6 +1157,10 @@ screenData: type: String value: stringValue: "f3k" + 2: + type: String + value: + stringValue: "FXX" options: 0: type: Bool @@ -1156,11 +1193,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K" 1: widgetName: "SoarETX" widgetData: @@ -1168,11 +1209,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: stringValue: "wing2" + 2: + type: String + value: + stringValue: "F3K" 2: widgetName: "SoarETX" widgetData: @@ -1180,11 +1225,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "f3k_mix" + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K" 3: widgetName: "SoarETX" widgetData: @@ -1192,11 +1241,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "f3k_ctr" + stringValue: "ailctr" + 2: + type: String + value: + stringValue: "F3K" 4: widgetName: "SoarETX" widgetData: @@ -1204,11 +1257,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: stringValue: "graph" + 2: + type: String + value: + stringValue: "F3K" 5: widgetName: "SoarETX" widgetData: @@ -1216,11 +1273,15 @@ screenData: 0: type: Signed value: - signedValue: 1 + signedValue: 2 1: type: String value: - stringValue: "f3k_sw" + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K" options: 0: type: Bool @@ -1256,6 +1317,10 @@ topbarData: type: String value: stringValue: "name" + 2: + type: String + value: + stringValue: "FXX" 3: widgetName: "SoarETX" widgetData: @@ -1268,5 +1333,23 @@ topbarData: type: String value: stringValue: "battery" + 2: + type: String + value: + stringValue: "FXX" view: 1 -modelRegistrationID: "" +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.txt new file mode 100644 index 00000000..22dfe7be --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.txt @@ -0,0 +1 @@ +F5J Model (4 Servo Wings + Motor) \ No newline at end of file diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.yml b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.yml new file mode 100644 index 00000000..0bef2546 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/F5J_v2.yml @@ -0,0 +1,2382 @@ +semver: 2.9.1 +header: + name: "F5J_v2" + modelId: + 0: + val: 4 + bitmap: "" + labels: "" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "FM2" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Motor" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 6 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L36" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: GV5 + destCh: 21 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotEle" + - + weight: 10 + destCh: 21 + srcRaw: MAX + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotEle" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 22 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 22 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 50 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotCbr" + - + weight: 100 + destCh: 23 + srcRaw: ch(22) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: ch(22) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 550 + max: -550 + ppmCenter: 0 + offset: 44 + symetrical: 0 + revert: 1 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: -88 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 450 + max: -740 + ppmCenter: 0 + offset: -60 + symetrical: 0 + revert: 0 + curve: 1 + name: "LftAil" + 3: + min: 900 + max: -500 + ppmCenter: 0 + offset: 210 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 500 + max: -930 + ppmCenter: 0 + offset: -220 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 780 + max: -370 + ppmCenter: 0 + offset: 89 + symetrical: 0 + revert: 0 + curve: 2 + name: "RgtAil" + 6: + min: 20 + max: -20 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Motor" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 22: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CbrPS" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 3 + swtch: "NONE" + flightModes: 110111111 + weight: 100 + name: "On" + offset: 0 + curve: + type: 3 + value: 9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: -100 + name: "Off" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 8: + type: 1 + smooth: 0 + points: -1 + name: "Mot" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -49 + 8: + val: 48 + 9: + val: 100 + 10: + val: -100 + 11: + val: -39 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 54 + 19: + val: 100 + 20: + val: -100 + 21: + val: -50 + 23: + val: 35 + 24: + val: 70 + 25: + val: 98 + 26: + val: 73 + 27: + val: 47 + 28: + val: 20 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 54: + val: -70 + 55: + val: 75 + 56: + val: 100 + 57: + val: 100 + 58: + val: 90 + 59: + val: 90 + 60: + val: 100 + 62: + val: 100 + 63: + val: -100 + 64: + val: 100 + 65: + val: 100 + 66: + val: 90 + 167: + val: -48 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,!SC2" + andsw: "!FM2" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VEQUAL + def: "gv(8),1" + andsw: "NONE" + delay: 0 + duration: 0 + 20: + func: FUNC_AND + def: "!L9,!L26" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "L21" + delay: 0 + duration: 0 + 22: + func: FUNC_STICKY + def: "L22,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_EDGE + def: "L9,0,-" + andsw: "L23" + delay: 0 + duration: 1 + 24: + func: FUNC_AND + def: "L24,!L30" + andsw: "!FM1" + delay: 0 + duration: 0 + 25: + func: FUNC_STICKY + def: "L25,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_OR + def: "!L5,L26" + andsw: "NONE" + delay: 0 + duration: 0 + 27: + func: FUNC_OR + def: "!L5,L9" + andsw: "L26" + delay: 0 + duration: 0 + 28: + func: FUNC_VEQUAL + def: "TIMER2,30" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_OR + def: "L28,L29" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 33: + func: FUNC_OR + def: "L26,L32" + andsw: "NONE" + delay: 0 + duration: 0 + 34: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L34" + delay: 0 + duration: 0 + 35: + func: FUNC_STICKY + def: "L34,L35" + andsw: "NONE" + delay: 0 + duration: 0 + 36: + func: FUNC_AND + def: "L36,!L34" + andsw: "!L35" + delay: 30 + duration: 0 + 38: + func: FUNC_AND + def: "L10,FM2" + andsw: "L19" + delay: 0 + duration: 0 + 39: + func: FUNC_AND + def: "L10,!FM2" + andsw: "L19" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM2" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 3: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 4: + swtch: "L2" + func: VARIO + def: "" + 5: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 6: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER1,10" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 10: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 12: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 16: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 20: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 21: + swtch: "!L23" + func: PLAY_TRACK + def: "disarm,!1x" + 22: + swtch: "L23" + func: PLAY_TRACK + def: "motarm,5" + 23: + swtch: "L24" + func: RESET + def: "Tmr2,1" + 24: + swtch: "L28" + func: PLAY_TRACK + def: "engoff,!1x" + 25: + swtch: "L37" + func: PLAY_TRACK + def: "flapup,5" + 26: + swtch: "L39" + func: LOGS + def: "5" + 27: + swtch: "L40" + func: LOGS + def: "10" + 28: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 29: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" + 30: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 31: + swtch: "FM2" + func: PLAY_TRACK + def: "power,1x" +flightModeData: + 0: + trim: + 4: + value: 84 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 10 + 2: + val: 20 + 3: + val: 30 + 4: + val: 9 + 5: + val: 49 + 6: + val: 24 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 2: + value: -40 + mode: 4 + name: "Motor" + swtch: "L26" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L32" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 54 + mode: 1 + 2: + value: -128 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: Hu +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 3 + centerSilent: 1 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 64,0 + channelsStart: 0 + channelsCount: 8 + failsafeMode: CUSTOM + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + receiverTelemetryOff: 0 + receiverHigherChannels: 0 + optionValue: 0 +failsafeChannels: + 0: + val: -45 + 1: + val: -90 + 2: + val: -61 + 3: + val: 20 + 4: + val: -9 + 5: + val: 91 + 6: + val: -1004 + 8: + val: -1 + 9: + val: -1 + 10: + val: 716 + 11: + val: 716 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 3: + val: "Moto" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 61697 + id2: + instance: 24 + label: "RSSI" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + id1: + id: 65534 + id2: + instance: 248 + label: "TRSS" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 2: + id1: + id: 65533 + id2: + instance: 248 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 256 + id2: + instance: 26 + label: "Alt" + subId: 0 + type: TYPE_CUSTOM + unit: 9 + prec: 1 + autoOffset: 1 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + id1: + id: 61700 + id2: + instance: 24 + label: "RxBt" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 5: + id1: + id: 272 + id2: + instance: 26 + label: "VSpd" + subId: 0 + type: TYPE_CUSTOM + unit: 5 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + id1: + id: 61699 + id2: + instance: 26 + label: "A2" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x105C98 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0xE0ECF0 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + 2: + widgetName: "Timer" + widgetData: + options: + 0: + type: Unsigned + value: + unsignedValue: 1 + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F5J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F5J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F5J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F5J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F5J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F5J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f5j" + 2: + type: String + value: + stringValue: "" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "FXX" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 3 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/about.txt b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/about.txt new file mode 100644 index 00000000..fb318d02 --- /dev/null +++ b/sdcard/c480x272/TEMPLATES/4.SoarETX_v2/about.txt @@ -0,0 +1,4 @@ +A collection of sailplane templates with Lua widgets for timing, score keeping, graphing of log data, and model configuration. + +Author: Jesper Frickmann +Author: Frankie Arzu (v2) \ No newline at end of file diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua index 4ddbbe04..071de004 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/brkcrv.lua @@ -3,7 +3,7 @@ -- -- -- Author: Jesper Frickmann -- -- Date: 2022-08-20 -- --- Version: 1.0.0 -- +-- Version: 1.0.2 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -61,7 +61,7 @@ end -- Make sure that we have the right number of points on the curve local function GetCurve(crvIndex) - local tbl = model.getCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) if #tbl.y ~= N then stepOff() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua index 0780e7ff..1526c149 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/wing2.lua @@ -3,7 +3,7 @@ -- -- -- Author: Jesper Frickmann -- -- Date: 2022-06-26 -- --- Version: 1.0.1 -- +-- Version: 1.0.2 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -66,10 +66,11 @@ local activeP -- The point currently being edited -- Make sure that we have the right number of points on the curve local function GetCurve(crvIndex) - local tbl = model.getCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) if #tbl.y ~= N then setStickySwitch(LS_STEP, false) + gui= nil error("Wrong number of points on curve CV" .. crvIndex + 1) end diff --git a/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua b/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua index 540a52ad..db35e1a0 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/1/wing4.lua @@ -3,7 +3,7 @@ -- -- -- Author: Jesper Frickmann -- -- Date: 2022-08-20 -- --- Version: 1.0.0 -- +-- Version: 1.0.2 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -79,7 +79,7 @@ end -- Make sure that we have the right number of points on the curve local function GetCurve(crvIndex) - local tbl = model.getCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) if #tbl.y ~= N then stepOff() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua new file mode 100644 index 00000000..510ee947 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/ailctr.lua @@ -0,0 +1,183 @@ +--------------------------------------------------------------------------- +-- SoarETX Center ailerons, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-19 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Center ailerons" +local slider + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 20 +local TOP = HEADER + MARGIN +local SLIDER_X = LCD_W - 30 +local SLIDER_W = 50 +local SLIDER_H = 200 +local R2 = (LCD_H - TOP - MARGIN) / 1.707 +local R1 = R2 - 35 +local CTR_X = LCD_W / 2 +local CTR_Y = TOP + 0.707 * R2 +local SML_H = select(2, lcd.sizeText("", SMLSIZE)) + +-- Global variables +local GV_AIL = 0 -- Aileron travel +local GV_BRK = 1 -- Air brake travel +local GV_DIF = 3 -- Aileron differential + +-- Logical switch to disable camber etc. to center +local LS_CTR = 11 + +-- Special: blend two theme colors +local COLOR_BLEND +do + local c1 = lcd.getColor(COLOR_THEME_SECONDARY1) + local b1 = 8 * bit32.band(bit32.rshift(c1, 16), 0x1F) + local g1 = 4 * bit32.band(bit32.rshift(c1, 21), 0x3F) + local r1 = 8 * bit32.band(bit32.rshift(c1, 27), 0x1F) + + local c2 = lcd.getColor(COLOR_THEME_SECONDARY2) + local b2 = 8 * bit32.band(bit32.rshift(c2, 16), 0x1F) + local g2 = 4 * bit32.band(bit32.rshift(c2, 21), 0x3F) + local r2 = 8 * bit32.band(bit32.rshift(c2, 27), 0x1F) + + COLOR_BLEND = lcd.RGB((r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2) +end + +-- Draw radial line +local function drawRadian(deg) + deg = deg * math.pi / 180 + local x = CTR_X + R2 * math.sin(deg) + local y = CTR_Y - R2 * math.cos(deg) + lcd.drawLine(CTR_X, CTR_Y, x, y, SOLID, colors.primary3) +end + +-- Draw label on annulus +local function drawLabel(deg, r, txt, color) + deg = deg * math.pi / 180 + local x = CTR_X + r * math.sin(deg) + local y = CTR_Y - r * math.cos(deg) + lcd.drawText(x, y, txt, CENTER + VCENTER + SMLSIZE + color) +end + +-- Adjust global variables +local function adjust(slider) + -- Compensate for possible negative differential + local dif = model.getGlobalVariable(GV_DIF, 0) + local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) + -- Calculate aileron travel from current airbrake travel + local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) + model.setGlobalVariable(GV_AIL, 0, ail) + model.setGlobalVariable(GV_BRK, 0, slider.value) +end + +-------------------------------- Setup GUI -------------------------------- + +do + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Illustration of flap and aileron travel + local ail = model.getGlobalVariable(GV_AIL, 0) + local ailDeg = 0.45 * ail + local brk = 2 * model.getGlobalVariable(GV_BRK, 0) + local brkDeg = 0.45 * brk + local dif = 0.01 * model.getGlobalVariable(GV_DIF, 0) + + lcd.drawPie(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 91 + brkDeg, colors.primary2) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 + ailDeg * math.min(1, 1 - dif), 90 + brkDeg, COLOR_THEME_SECONDARY2) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90, 90 + ailDeg * math.min(1, 1 - dif), COLOR_BLEND) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 - ailDeg * math.min(1, 1 + dif), 90, COLOR_THEME_SECONDARY1) + + lcd.drawArc(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 90 + brkDeg, colors.primary3) + drawRadian(90 - ailDeg * math.min(1, 1 + dif)) + drawRadian(90) + drawRadian(90 + brkDeg) + + lcd.drawFilledCircle(CTR_X, CTR_Y, 2, colors.primary2) + lcd.drawCircle(CTR_X, CTR_Y, 3, colors.primary3) + lcd.drawCircle(CTR_X, CTR_Y, 2, colors.primary3) + + lcd.drawFilledCircle(CTR_X + R2, CTR_Y, 4, colors.edit) + lcd.drawCircle(CTR_X + R2, CTR_Y, 5, colors.primary3) + lcd.drawCircle(CTR_X + R2, CTR_Y, 4, colors.primary3) + + drawLabel(90 - ailDeg / 2 * math.min(1, 1 + dif), (R1 + R2) / 2, math.floor(ail * math.min(1, 1 + dif) + 0.5) .. "%", colors.primary2) + drawLabel(90 + math.min(brkDeg - 10, (ailDeg + brkDeg) / 2), (R1 + R2) / 2, math.floor(brk + 0.5) .. "%", colors.primary1) + lcd.drawText(CTR_X + R1, CTR_Y - SML_H, "aileron ", RIGHT + SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R1, CTR_Y, "brake ", RIGHT + SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R2, CTR_Y - SML_H, " max.", SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R2, CTR_Y, " reflex", SMLSIZE + colors.primary1) + + local txt = "Use the slider to adjust the flaperons to the position of maximum reflex.\n\n" .. + "Notice that camber can only move the flaperons down from this position." + lcd.drawTextLines(MARGIN, TOP, CTR_X - 2 * MARGIN, LCD_H - TOP - MARGIN, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + slider = gui.verticalSlider(SLIDER_X, TOP, SLIDER_H, 70, 50, 90, 1, adjust) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if getLogicalSwitchValue(LS_CTR) then + setStickySwitch(LS_CTR, false) + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif not getLogicalSwitchValue(LS_CTR) then + setStickySwitch(LS_CTR, true) + slider.value = model.getGlobalVariable(GV_BRK, 0) + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/battery.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/battery.lua new file mode 100644 index 00000000..a0a10b95 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/battery.lua @@ -0,0 +1,35 @@ +--------------------------------------------------------------------------- +-- SoarETX, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-11-21 -- +-- Version: 1.0.1 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... + +function widget.refresh(event, touchState) + if event then + lcd.exitFullScreen() + end + local flags = CENTER + VCENTER + MIDSIZE + if soarGlobals.battery and soarGlobals.battery > 0 then + flags = flags + COLOR_THEME_PRIMARY2 + else + flags = flags + COLOR_THEME_DISABLED + end + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, string.format("%1.1f V", soarGlobals.battery), flags) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua new file mode 100644 index 00000000..8b0b2d65 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/brkcrv.lua @@ -0,0 +1,225 @@ +--------------------------------------------------------------------------- +-- SoarETX Adjust airbrake curves for flaps and ailerons -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-20 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = nil +local colors = libGUI.colors +local title = "Airbrake curves" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 40 +local HEIGHT = 150 +local WIDTH = (LCD_W - 3 * DIST_X) / 2 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 +local TEXT_Y = BUTTON_Y + +-- Global variables +local INP_STEP = getFieldInfo("input8").id -- Step input for selecting curve point +local LS_STEP = 11 -- Set this LS to apply step input +local N = 5 -- Number of points on the curves +local MAX_Y = 100 -- Max plot value +local CRV_FLP = 4 -- Index of the flap curve +local CRV_AIL = 5 -- Index of the aileron curve +local tblFlp -- Table with data for the flap curve +local tblAil -- Table with data for the aileron curve +local activeP -- The point currently being edited +local stepOn = false -- Step input has be turned on by this widget + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if stepOn then + stepOn = false + setStickySwitch(LS_STEP, false) + end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +local function init() + tblFlp = GetCurve(CRV_FLP) + tblAil = GetCurve(CRV_AIL) + setStickySwitch(LS_STEP, true) + stepOn = true +end -- init() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjust a point, either on a curve or output +local function adjustPoint(crvIdx, crvTbl, slider) + crvTbl.y[activeP] = slider.value + model.setCurve(crvIdx, crvTbl) +end + +-- Reset curves to defaults +local function reset() + local ys = { -100, -50, 0, 25, 50 } + for i, y in ipairs(ys) do + tblFlp.y[i] = y + end + model.setCurve(CRV_FLP, tblFlp) + + ys = { -50, -50, -50, -25, 0 } + for i, y in ipairs(ys) do + tblAil.y[i] = y + end + model.setCurve(CRV_AIL, tblAil) +end +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + + gui = libGUI.newGUI() + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + drawCurve(DIST_X, TOP, WIDTH, HEIGHT, tblFlp.y) + lcd.drawText(DIST_X + 2, TOP, "Flaps", SMLSIZE + colors.primary1) + + drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, tblAil.y) + lcd.drawText(WIDTH + 2 * DIST_X + 2, TOP, "Aileron", SMLSIZE + colors.primary1) + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + local flpSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_FLP, tblFlp, slider) end) + + function flpSlider.update() + flpSlider.value = tblFlp.y[activeP] + end + + local ailSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_AIL, tblAil, slider) end) + + function ailSlider.update() + ailSlider.value = tblAil.y[activeP] + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if (gui ~= nil) then + stepOff() + gui = nil + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = math.floor((N - 1) / 2048 * (getValue(INP_STEP) + 1024) + 1.5) + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua new file mode 100644 index 00000000..0872dad9 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f3J.lua @@ -0,0 +1,351 @@ +--------------------------------------------------------------------------- +-- SoarETX F3J score keeper, loadable component -- +-- -- +-- Author: Frankie Arzu / Jesper Frickmann -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors + +-- GUIs for the different screens and popups +local screenTask = libGUI.newGUI() + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W) / 2 +local BOT_ROW = LCD_H - 60 + +-- Constants +local LS_ALT = 0 -- LS1 allowing altitude calls +local LS_ALT10 = 7 -- LS8 for altitude calls every 10 sec. + +local LS_TRIGGER = 8 -- LS9 + +local GV_FLT_TMR = 8 -- GV8 for the flight timer +local FM_LAUNCH = 2 -- Launch flight mode + +-- Program states +local STATE_INITIAL = 0 -- Set flight time before the flight +local STATE_WINDOW = 1 -- Task window is active +local STATE_FLYING = 2 -- Flight timer is running +local STATE_LANDINGPTS = 3 -- Landed, input landing points +local STATE_TIME = 4 -- Input flight time +local STATE_SAVE = 5 -- Ready to save +local state -- Current program state + +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevTrig = false -- Previous vakue of Trigger +local prevWt -- Previous Window Time + +-- Other common variables +--local counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} -- Flight timer countdown +--local countIndex -- Index of timer count + +--local flightTimer -- Flight timer +local windowTimer -- Window Timer + +local callAlt = false + +local startHeight = 0 +local altTime = 0 +local landingPts = 0 + + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F3J Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + print("GotoState:" .. newState) + + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state == STATE_INITIAL then + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + + screenTask.labelInfo.title = "INITIAL" + screenTask.locked = false + elseif state == STATE_WINDOW then + model.setGlobalVariable(GV_FLT_TMR, 0, 1) -- Window Open + playTone(1760, 100, PLAY_NOW) + + screenTask.labelInfo.title = "Window Open" + screenTask.locked = true + elseif state == STATE_FLYING then + model.setGlobalVariable(GV_FLT_TMR, 0, 2) -- Flying + playTone(1760, 100, PLAY_NOW) + + screenTask.labelInfo.title = "Soaring.." + screenTask.locked = true + elseif state == STATE_LANDINGPTS then + screenTask.labelInfo.title = "Landed. Launch Alt =" .. startHeight + elseif state == STATE_TIME then + screenTask.labelInfo.title = "TODO:Enter Time/Landing" + elseif state == STATE_SAVE then + screenTask.labelInfo.title = "TODO:Save Data" + end + + -- Configure "button3" + --screenTask.button3.disabled = false + --screenTask.button3.title = "Button3" + + -- Configure info text label + --screenTask.labelInfo.title = " Info Label" +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName) + screenTask.title = taskName +end -- SetupTask(...) + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +local function TargetTime() + return model.getTimer(0).start +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + --countIndex = #counts + --while countIndex > 1 and counts[countIndex] >= targetTime do + -- countIndex = countIndex - 1 + --end + + -- Set Window timer + model.setTimer(0, { start = targetTime, value = targetTime }) + model.setTimer(1, { start = 0, value = 0 }) + + landingPts = 0 + startHeight = 100 -- default if no Alt + + GotoState(STATE_INITIAL) +end -- InitializeFlight() + +local function playWindowTime(windowTimer) + local wt = windowTimer.value -- Current window timer value + local cnt -- Count interval + + if wt > 120 then + cnt = 60 + elseif wt > 60 then + cnt = 15 + elseif wt > 10 then + cnt = 5 + else + cnt = 1 + end + + if math.ceil(prevWt / cnt) > math.ceil(wt / cnt) then + if wt > 10 then + playDuration(wt, 0) + elseif wt > 0 then + playNumber(wt, 0) + end + end + + -- Stop flight when the window expires + if wt <= 0 and prevWt > 0 then + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + end + + prevWt = wt +end -- PlayWindowTimer + +local function inAltitudeWindow() + -- Record (and announce) start height + if altTime > 0 and getTime() > altTime then + startHeight = getValue("Alt+") + altTime = 0 + + -- Call launch height + if callAlt then + playNumber(startHeight, UNIT_METERS) + end + + if startHeight == 0 then startHeight = 100 end -- If no altimeter; default to 100 + end +end -- InAltitudeWindow + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + + local launchOn = (flightMode == FM_LAUNCH) and prevFM ~= flightMode -- Launch Activated + + local triggerNow = getLogicalSwitchValue(LS_TRIGGER) + prevTrig, triggerNow = triggerNow, triggerNow and not prevTrig + + prevFM = flightMode + + callAlt = (getLogicalSwitchValue(LS_ALT10)) -- Call alt every 10 sec. + + windowTimer = model.getTimer(0) -- Current motor timer value + flightTimer = model.getTimer(1) -- Current flight timer value + + if state == STATE_INITIAL then + landingPts = 0 + startHeight = 0 -- default if no Alt + + -- Move to Window Open + if triggerNow then + GotoState(STATE_WINDOW) + ResetAlt() + + prevWt = model.getTimer(0).value + + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + end + elseif state == STATE_WINDOW then + if triggerNow then -- Trigger switch released + GotoState(STATE_FLYING) + + -- Start 10s Altitude recording window + altTime = getTime() + 1000 + startHeight = getValue("Alt+") + end + elseif state == STATE_FLYING then + if (launchOn) then -- Reflight + GotoState(STATE_WINDOW) + model.setTimer(1, { start = 0, value = 0 }) -- Flight Timer + return + end + + inAltitudeWindow() + playWindowTime(windowTimer) + + if triggerNow then + -- Stop timer and record scores + playTone(1760, 100, PLAY_NOW) + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + GotoState(STATE_LANDINGPTS) + end + + -- STATE_GLIDE + elseif state == STATE_LANDINGPTS then + if triggerNow then + GotoState(STATE_TIME) + end + elseif state == STATE_TIME then + if triggerNow then + GotoState(STATE_SAVE) + end + elseif state == STATE_SAVE then + if triggerNow then + InitializeFlight() + GotoState(STATE_INITIAL) + end + end +end -- background() + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = (widget.zone.w / 2) - 198 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + -- Draw timers + local blink = 0 + local y = 1 + + local tmr = model.getTimer(0).value -- Window + if tmr < 0 and state > STATE_FLYING then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + + tmr = model.getTimer(1).value -- Flight Timer + lcd.drawText(COL3, y + 10, screenTask.labelTimer1.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) + y = y + 2 * dy + lcd.drawText(COL1, y, screenTask.labelInfo.title, colors.primary1 + DBLSIZE) +end -- widgetRefresh() + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + --screenTask.run(event,touchState + libGUI.widgetRefresh() +end -- refresh(...) + +local function SetupScreenTask() + print("SetupScreenTask:Begin") + local y + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, " Info ", libGUI.flags + RIGHT) + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Window:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.labelTimer1 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Flight:", MIDSIZE) + y = y + LINE2 + screenTask.timer1 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer1.disabled = true + print("SetupScreenTask:End") +end + + +-- Initialize stuff +SetupScreenTask() +SetupTask("10 Min Window") +InitializeFlight() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua new file mode 100644 index 00000000..7592147a --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f3k.lua @@ -0,0 +1,1264 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K score keeper, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2023-01-23 -- +-- Version: 1.0.2 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors +local activeGUI + +-- GUIs for the different screens and popups +local menuMain = libGUI.newGUI() +local menuF3K = libGUI.newGUI() +local menuPractice = libGUI.newGUI() +local screenTask = libGUI.newGUI() +local promptSaveScores = libGUI.newGUI() +local menuScores = { } + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W)/2 +local BOT_ROW = LCD_H - 60 + +-- Input sources for the trim buttons +local trimSources = { + getFieldInfo("trim-ail").id, + getFieldInfo("trim-rud").id, + getFieldInfo("trim-ele").id, + getFieldInfo("trim-thr").id +} + +-- Constants +local LS_ALT = 0 -- LS allowing altitude calls +local LS_ALT10 = 5 -- LS for altitude calls every 10 sec. +local LS_WIN_TMR = 14 -- LS for the window timer +local LS_FLT_TMR = 15 -- LS for the flight timer + +local FM_LAUNCH = 1 -- Launch/motor flight mode + +-- Program states +local STATE_IDLE = 1 -- Task window not running +local STATE_PAUSE = 2 -- Task window paused, not flying +local STATE_FINISHED = 3 -- Task has been finished +local STATE_WINDOW = 4 -- Task window started, not flying +local STATE_READY = 5 -- Flight timer will be started when launch switch is released +local STATE_FLYING = 6 -- Flight timer started but flight not yet committed +local STATE_COMMITTED = 7 -- Flight timer started, and flight committed +local STATE_FREEZE = 8 -- Still committed, but freeze the flight timer +local state -- Current program state + +-- Common variables for score keeping +local scores = { } -- List of saved scores +local taskWindow = 0 -- Task window duration (zero counts up) +local launches = -1 -- Number of launches allowed, -1 for unlimited +local taskScores = 0 -- Number of scores in task +local finalScores = false -- Task scores are final +local targetType = 0 -- 1. Huge ladder, 2. Poker, 3. "1234", 4. Big ladder, Else: constant time +local scoreType -- 1. Best, 2. Last, 3. Make time +local totalScore -- Total score +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevWt -- Previous value of the window timer +local prevFt -- Previous value of flight timer + +-- Other common variables +local counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} -- Flight timer countdown +local countIndex -- Index of timer count +local nextCall = 0 -- Call out altitude every 10 sec. +local winTimer = 0 -- Window timer +local flightTimer -- Flight timer +local flightTime -- Flight flown + +-- Variables used for Poker task +local pokerCalled -- Lock in time in Poker task +local lastInput = 0 -- For announcing changes in PokerCall +local lastChange = 0 -- Same +local tblStep = { {30, 5}, {60, 10}, {120, 15}, {210, 30}, {420, 60} } -- Step sizes for input of call time + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F3K Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state < STATE_WINDOW or state == STATE_FREEZE then + setStickySwitch(LS_WIN_TMR, false) + setStickySwitch(LS_FLT_TMR, false) + screenTask.labelTimer0.title = "Target:" + screenTask.locked = false + + elseif state == STATE_WINDOW then + setStickySwitch(LS_WIN_TMR, true) + setStickySwitch(LS_FLT_TMR, false) + screenTask.labelTimer0.title = "Target:" + screenTask.locked = true + + elseif state == STATE_FLYING then + setStickySwitch(LS_WIN_TMR, true) + setStickySwitch(LS_FLT_TMR, true) + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + + if model.getTimer(0).start > 0 then + -- Report the target time + playDuration(model.getTimer(0).start, 0) + else + -- ... or beep + playTone(1760, 100, PLAY_NOW) + end + + elseif state == STATE_COMMITTED then + -- Call launch height + if getLogicalSwitchValue(LS_ALT) then + playNumber(getValue("Alt+"), UNIT_METERS) + end + + if launches > 0 then + launches = launches - 1 + end + + lastChange = 0 + + elseif state == STATE_FINISHED then + playTone(880, 1000, 0) + end + + -- Configure "button3" + screenTask.button3.disabled = false + if state <= STATE_PAUSE then + screenTask.button3.title = "Start" + elseif state == STATE_WINDOW then + screenTask.button3.title = "Pause" + elseif state >= STATE_COMMITTED then + screenTask.button3.title = "Zero" + else + screenTask.button3.disabled = true + end + + -- Configure info text label + if state == STATE_PAUSE then + screenTask.labelInfo.title = string.format("Total: %i sec.", totalScore) + elseif state == STATE_FINISHED then + screenTask.labelInfo.title = string.format("Done! %i sec.", totalScore) + else + if launches >= 0 then + local s = "" + if launches ~= 1 then s = "es" end + screenTask.labelInfo.title = string.format("%i launch%s left", launches, s) + else + screenTask.labelInfo.title = "" + end + end +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName, taskData) + screenTask.title = taskName + + taskWindow = taskData[1] + launches = taskData[2] + taskScores = taskData[3] + finalScores = taskData[4] + targetType = taskData[5] + scoreType = taskData[6] + screenTask.buttonQR.value = taskData[7] + scores = { } + totalScore = 0 + pokerCalled = false + + -- Setup scores + for i = 1, N_LINES do + if i > taskScores then + screenTask.scoreLabels[i].hidden = true + screenTask.scores[i].hidden = true + else + screenTask.scoreLabels[i].hidden = false + screenTask.scores[i].hidden = false + end + end + + -- A few extra counts in 1234 + if targetType == 3 then + counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45, 65, 70, 75, 125, 130, 135, 185, 190, 195} + else + counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} + end + + GotoState(STATE_IDLE) +end -- SetupTask(...) + +-- Keep the best scores +local function RecordBest(scores, newScore) + local n = #scores + local i = 1 + local j = 0 + + -- Find the position where the new score is going to be inserted + if n == 0 then + j = 1 + else + -- Find the first position where existing score is smaller than the new score + while i <= n and j == 0 do + if newScore > scores[i] then j = i end + i = i + 1 + end + + if j == 0 then j = i end -- New score is smallest; end of the list + end + + -- If the list is not yet full; let it grow + if n < taskScores then n = n + 1 end + + -- Insert the new score and move the following scores down the list + for i = j, n do + newScore, scores[i] = scores[i], newScore + end +end -- RecordBest (...) + +-- Used for calculating the total score and sometimes target time +local function MaxScore(iFlight) + if targetType == 1 then -- Huge ladder + return 60 + 120 * iFlight + elseif targetType == 2 then -- Poker + return 9999 + elseif targetType == 3 then -- 1234 + return 300 - 60 * iFlight + elseif targetType == 4 then -- Big ladder + return 30 + 30 * iFlight + else -- MaxScore = targetType + return targetType + end +end + +-- Record scores +local function Score() + if scoreType == 1 then -- Best scores + RecordBest(scores, flightTime) + + elseif scoreType == 2 then -- Last scores + local n = #scores + if n >= taskScores then + -- List is full; move other scores one up to make room for the latest at the end + for j = 1, n - 1 do + scores[j] = scores[j + 1] + end + else + -- List can grow; add to the end of the list + n = n + 1 + end + scores[n] = flightTime + + else -- Must make time to get score + local score = flightTime + -- Did we make time? + if flightTimer > 0 then + return + else + -- In Poker, only score the call + if pokerCalled then + score = model.getTimer(0).start + pokerCalled = false + end + end + scores[#scores + 1] = score + + end + + totalScore = 0 + for i = 1, #scores do + totalScore = totalScore + math.min(MaxScore(i), scores[i]) + end +end -- Score() + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +-- Find the best target time, given what has already been scored, as well as the remaining time of the window. +-- Note: maxTarget ensures that recursive calls to this function only test shorter target times. That way, we start with +-- the longest flight and work down the list. And we do not waste time testing the same target times in different orders. +local function Best1234Target(timeLeft, scores, maxTarget) + local bestTotal = 0 + local bestTarget = 0 + + -- Max. minutes there is time left to fly + local maxMinutes = math.min(maxTarget, 4, math.ceil(timeLeft / 60)) + + -- Iterate from 1 to n minutes to find the best target time + for i = 1, maxMinutes do + local target + local tl + local tot + local dummy + + -- Target in seconds + target = 60 * i + + -- Copy scores to a new table + local s = {} + for j = 1, #scores do + s[j] = scores[j] + end + + -- Add new target time to s; only until the end of the window + RecordBest(s, math.min(timeLeft, target)) + tl = timeLeft - target + + -- Add up total score, assuming that the new target time was made + if tl <= 0 or i == 1 then + -- No more flights are made; sum it all up + tot = 0 + for j = 1, math.min(4, #s) do + tot = tot + math.min(300 - 60 * j, s[j]) + end + else + -- More flights can be made; add more flights recursively + -- Subtract one second from tl for turnaround time + dummy, tot = Best1234Target(tl - 1, s, i - 1) + end + + -- Do we have a new winner? + if tot > bestTotal then + bestTotal = tot + bestTarget = target + end + end + + return bestTarget, bestTotal +end -- Best1234Target(..) + +-- Get called time from user in Poker +local function PokerCall() + local dial + + -- Find dials for setting target time in Poker and height ceilings etc. + for input = 0, 31 do + local tbl = model.getInput(input, 0) + + if tbl and tbl.name == "Dial" then + dial = tbl.source + end + end + + -- If input lines were not found, then default to S1 and S2 + if not dial then dial = getFieldInfo("s1").id end + + local input = getValue(dial) + local i, x = math.modf(1 + #tblStep * (math.min(1023, input) + 1024) / 2048) + local t1 = tblStep[i][1] + local t2 + if i >= #tblStep then + t2 = math.max(600, taskWindow) + 60 + else + t2 = tblStep[i + 1][1] + end + local dt = tblStep[i][2] + + local result = t1 + dt * math.floor(x * (t2 - t1) /dt) + + if scoreType == 3 then + result = math.min(winTimer - 1, result) + end + + if math.abs(input - lastInput) >= 20 then + lastInput = input + lastChange = getTime() + end + + if state == STATE_COMMITTED and lastChange > 0 and getTime() - lastChange > 100 then + playTone(3000, 100, PLAY_NOW) + playDuration(result) + lastChange = 0 + end + + return result +end -- PokerCall() + +local function TargetTime() + if targetType == 2 then -- Poker + if pokerCalled then + return model.getTimer(0).start + else + return PokerCall() + end + elseif targetType == 3 then -- 1234 + return Best1234Target(winTimer, scores, 4) + elseif targetType == 5 then -- Deuces + if #scores == 0 then + return math.max(0, math.floor(winTimer / 2)) + elseif #scores == 1 then + return math.max(0, math.min(winTimer, scores[1])) + else + return 0 + end + else -- All other tasks + return MaxScore(#scores + 1) + end +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + countIndex = #counts + while countIndex > 1 and counts[countIndex] >= targetTime do + countIndex = countIndex - 1 + end + + -- Set flight timer + model.setTimer(0, { start = targetTime, value = targetTime }) + flightTimer = targetTime + prevFt = targetTime +end -- InitializeFlight() + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + local launchPulled = (flightMode == FM_LAUNCH and prevFM ~= flightMode) + local launchReleased = (flightMode ~= prevFM and prevFM == FM_LAUNCH) + prevFM = flightMode + + -- Reset altitude + if launchPulled then + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + + ResetAlt() + end + + -- Call altitude every 10 sec. + if getLogicalSwitchValue(LS_ALT10) and now > nextCall then + playNumber(getValue("Alt"), UNIT_METERS) + nextCall = now + 1000 + end + + if state <= STATE_READY and state ~= STATE_FINISHED then + InitializeFlight() + end + + flightTimer = model.getTimer(0).value + flightTime = math.abs(model.getTimer(0).start - flightTimer) + winTimer = model.getTimer(1).value + + if state < STATE_WINDOW then + if state == STATE_IDLE then + -- Set window timer + model.setTimer(1, { start = taskWindow, value = taskWindow }) + winTimer = taskWindow + prevWt = taskWindow + + -- Automatically start window and flight if launch switch is released + if launchPulled then + GotoState(STATE_READY) + end + end + + else + -- Did the window expire? + if prevWt > 0 and winTimer <= 0 then + playTone(880, 1000, 0) + + if state < STATE_FLYING then + GotoState(STATE_FINISHED) + elseif screenTask.buttonEoW.value then + GotoState(STATE_FREEZE) + end + end + + if state == STATE_WINDOW then + if launchPulled then + GotoState(STATE_READY) + elseif launchReleased then + -- Play tone to warn that timer is NOT running + playTone(1760, 200, 0, PLAY_NOW) + end + + elseif state == STATE_READY then + if launchReleased then + GotoState(STATE_FLYING) + end + + elseif state >= STATE_FLYING then + -- Time counts + if flightTimer <= counts[countIndex] and prevFt > counts[countIndex] then + if flightTimer > 15 then + playDuration(flightTimer, 0) + else + playNumber(flightTimer, 0) + end + if countIndex > 1 then countIndex = countIndex - 1 end + elseif flightTimer > 0 and math.ceil(flightTimer / 60) < math.ceil(prevFt / 60) then + playDuration(flightTimer, 0) + end + + -- Blink when flight ttimer is negative + if flightTimer < 0 then + screenTask.timer0.blink = true + end + + if state == STATE_FLYING then + -- Within 10 sec. "grace period", cancel the flight + if launchPulled then + GotoState(STATE_WINDOW) + end + + -- After 10 seconds, commit flight + if flightTime >= 10 then + GotoState(STATE_COMMITTED) + end + + elseif launchPulled then + -- Report the time after flight is done + if model.getTimer(0).start == 0 then + playDuration(flightTime, 0) + end + + Score() + + -- Change state + if (finalScores and #scores == taskScores) or launches == 0 or (taskWindow > 0 and winTimer <= 0) then + GotoState(STATE_FINISHED) + elseif screenTask.buttonQR.value then + GotoState(STATE_READY) + else + GotoState(STATE_WINDOW) + end + end + end + + prevWt = winTimer + prevFt = flightTimer + end + + -- Update info for user dial targets + if state == STATE_COMMITTED and targetType == 2 and (scoreType ~= 3 or taskScores - #scores > 1) then + local call = PokerCall() + local min = math.floor(call / 60) + local sec = call - 60 * min + screenTask.labelInfo.title = string.format("Next call: %02i:%02i", min, sec) + end + + -- "Must make time" tasks + if scoreType == 3 then + if state == STATE_COMMITTED then + pokerCalled = true + elseif state < STATE_FLYING and state ~= STATE_FINISHED and winTimer < TargetTime() then + GotoState(STATE_FINISHED) + end + end +end -- background() + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + activeGUI.run(event, touchState) +end -- refresh(...) + +-- Push new GUI as sub screen +local function PushGUI(gui) + gui.previous = activeGUI + activeGUI = gui +end + +-- Are we allowed to pop screen? +local function CanPopGUI() + return activeGUI.previous and not activeGUI.editing and not activeGUI.locked +end + +-- Pop GUI to return to previous screen +local function PopGUI() + if CanPopGUI() then + activeGUI = activeGUI.previous + return true + end +end + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = widget.zone.w / 2 - 200 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + for i = 1, taskScores do + lcd.drawText(COL1, y, string.format("%i.", i), colors.primary1 + DBLSIZE) + if i > #scores then + lcd.drawText(COL2, y, "- - -", colors.primary1 + DBLSIZE) + else + lcd.drawTimer(COL2, y, scores[i], colors.primary1 + DBLSIZE) + end + y = y + dy + end + + -- Draw timers + local blink = 0 + local y = 4 + + local tmr = model.getTimer(0).value + if tmr < 0 and state == STATE_COMMITTED then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + tmr = model.getTimer(1).value + lcd.drawText(COL3, y + 10, "Task:", colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) +end -- widgetRefresh() + + +-- Setup screen with title, trims, flight mode etc. +local function SetupScreen(gui, title, pop) + gui.title = title + local x1 + + if pop then + x1 = LCD_W - 80 + else + x1 = LCD_W - 50 + end + + function gui.fullScreenRefresh() + local color + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, gui.title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Date + local now = getDateTime() + local str = string.format("%02i:%02i", now.hour, now.min) + lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) + + if soarGlobals.battery == 0 then + color = COLOR_THEME_DISABLED + else + color = colors.primary2 + end + + str = string.format("%1.1fV", soarGlobals.battery) + lcd.drawText(x1 - 65, 6, str, RIGHT + MIDSIZE + color) + + -- Draw trims + local p = { + { LCD_W - 191, LCD_H - 14, 177, 8 }, + { 14, LCD_H - 14, 177, 8 }, + { LCD_W - 14, 68, 8, 177 }, + { 7, 68, 8, 177 }, + } + + for i = 1, 4 do + local q = p[i] + local value = getValue(trimSources[i]) / 10.24 + local x, y + if q[3] > q[4] then + x = q[1] + q[3] * (value + 100) / 200 + y = q[2] + q[4] / 2 + else + x = q[1] + q[3] / 2 + y = q[2] + q[4] * (100 - value) / 200 + end + + lcd.drawFilledRectangle(q[1], q[2], q[3], q[4], COLOR_THEME_SECONDARY1) + lcd.drawFilledRectangle(x - 9, y - 6, 18, 15, colors.primary1) + lcd.drawFilledRectangle(x - 10, y - 7, 18, 15, colors.focus) + lcd.drawNumber(x, y, value, SMLSIZE + VCENTER + CENTER + colors.primary2) + end + + -- Flight mode + lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) + end -- fullScreenRefresh() + + -- Return button + if pop then + gui.buttonRet = gui.custom({ }, LCD_W - 74, 6, 28, 28) + + function gui.buttonRet.draw(focused) + local color + + if CanPopGUI() then + color = colors.primary2 + gui.buttonRet.disabled = false + else + color = COLOR_THEME_DISABLED + gui.buttonRet.disabled = true + end + + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, color) + lcd.drawFilledRectangle(LCD_W - 61, 12, 3, 18, color) + for i = 0, 3 do + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, color) + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, color) + end + + if focused then + gui.buttonRet.drawFocus() + end + end + + function gui.buttonRet.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + PopGUI() + end + end + end + + -- Minimize button + local buttonMin = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonMin.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) + + if focused then + buttonMin.drawFocus() + end + end + + function buttonMin.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Short press EXIT to return to previous screen + local function HandleEXIT(event, touchState) + if PopGUI() then + return false + else + return event + end + end + gui.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) + + return gui +end -- SetupScreen + +-- Setup main menu +do + local WIDTH = 180 + local HEIGHT = 45 + local ROW = 65 + x = 40 + y = 60 + + SetupScreen(menuMain, "SoarETX F3K") + + -- Generate callbacks with closure for calling submenus + local function MakePush(subMenu) + return function() + PushGUI(subMenu) + end + end + + menuMain.button(x, y, WIDTH, HEIGHT, "F3K tasks", MakePush(menuF3K)) + y = y + ROW + menuMain.button(x, y, WIDTH, HEIGHT, "Practice", MakePush(menuPractice)) + y = y + ROW + menuMain.button(x, y, WIDTH, HEIGHT, "Scores", MakePush(menuScores)) + + activeGUI = menuMain +end + + +do -- Setup F3K tasks menu + SetupScreen(menuF3K, "F3K Tasks", true) + + local tasks = { + "A. Last flight", + "B. Two last 3:00", + "B. Two last 4:00", + "C. All up last down", + "D. Two flights only", + "E. Poker 10 min.", + "E. Poker 15 min.", + "F. Three best of six", + "G. Five best flights", + "H. 1-2-3-4 any order", + "I. Three best flights", + "J. Three last flights", + "K. Big Ladder", + "L. One flight only", + "M. Huge Ladder" + } + + -- {win, launches, scores, final, tgtType, scoType, QR } + local taskData = { + { 420, -1, 1, false, 300, 2, false }, -- A. Last flight + { 420, -1, 2, false, 180, 2, false }, -- B. Two last 3:00 + { 600, -1, 2, false, 240, 2, false }, -- B. Two last 4:00 + { 0, 5, 5, true, 180, 2, false }, -- C. AULD + { 600, 2, 2, true, 300, 2, true }, -- D. Two flights only + { 600, -1, 3, true, 2, 3, true }, -- E. Poker 10 min. + { 900, -1, 3, true, 2, 3, true }, -- E. Poker 15 min. + { 600, 6, 3, false, 180, 1, false }, -- F. 3 best of 6 + { 600, -1, 5, false, 120, 1, true }, -- G. 5 x 2:00 + { 600, -1, 4, false, 3, 1, true }, -- H. 1234 + { 600, -1, 3, false, 200, 1, true }, -- I. 3 Best + { 600, -1, 3, false, 180, 2, false }, -- J. 3 last + { 600, 5, 5, true, 4, 2, true }, -- K. Big ladder + { 600, 1, 1, true, 599, 2, false }, -- L. One flight only + { 900, 3, 3, true, 1, 2, true } -- M. Huge Ladder + } + + -- Call back function running when a menu item is selected + local function callBack(menu, event, touchState) + SetupTask(tasks[menu.selected], taskData[menu.selected]) + PushGUI(screenTask) + end + + menuF3K.menu(LEFT, TOP, LCD_W - 2 * LEFT, BOTTOM - TOP, tasks, callBack) +end + +do -- Setup practice tasks menu + SetupScreen(menuPractice, "Practice Tasks", true) + + local tasks = { + "Just Fly!", + "Quick Relaunch!", + "Deuces" + } + + -- {win, launches, scores, final, tgtType, scoType, QR } + local taskData = { + { 0, -1, 5, false, 0, 2, false }, -- Just fly + { 0, -1, 5, false, 2, 2, true }, -- QR + { 600, 2, 2, true, 5, 2, false } -- Deuces + } + + -- Call back function running when a menu item is selected + local function callBack(menu) + SetupTask(tasks[menu.selected], taskData[menu.selected]) + PushGUI(screenTask) + end + + menuPractice.menu(LEFT, TOP, LCD_W - 2 * LEFT, BOTTOM - TOP, tasks, callBack) +end + + +do -- Setup score keeper screen for F3K and Practice tasks + SetupScreen(screenTask, "", true) + + -- Restore default task and dismiss task screen + function screenTask.dismiss() + SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) + PopGUI() + end + + -- Return button shows prompt to save scores instead of popping right away + function screenTask.buttonRet.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + if state == STATE_IDLE then + screenTask.dismiss() + else + screenTask.showPrompt(promptSaveScores) + end + end + end + + -- Add score times + local y = TOP + local dy = select(2, lcd.sizeText("", libGUI.flags)) + + screenTask.scoreLabels = { } + screenTask.scores = { } + + for i = 1, N_LINES do + screenTask.scoreLabels[i] = screenTask.label(LEFT, y, 20, HEIGHT, string.format("%i.", i)) + + local s = screenTask.timer(LEFT + 40, y, 60, HEIGHT, 0, nil) + s.disabled = true + s.value = "- - -" + screenTask.scores[i] = s + + -- Modify timer's draw function to insert score value + local draw = s.draw + function s.draw(idx) + if i > #scores then + screenTask.scores[i].value = "- - -" + else + screenTask.scores[i].value = scores[i] + end + + draw(idx) + end + y = y + dy + end + + -- Add center buttons + local y = TOP + screenTask.buttonQR = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "QR", false, nil) + y = y + LINE + screenTask.buttonEoW = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "EoW", true, nil) + + local function callBack(button) + if state <= STATE_PAUSE then + GotoState(STATE_WINDOW) + + elseif state == STATE_WINDOW then + GotoState(STATE_PAUSE) + + elseif state >= STATE_COMMITTED then + -- Record a zero score! + flightTime = 0 + Score() + + -- Change state + if winTimer <= 0 or (finalScores and #scores == taskScores) or launches == 0 then + GotoState(STATE_FINISHED) + else + playTone(440, 333, PLAY_NOW) + GotoState(STATE_WINDOW) + end + end + end + + y = y + LINE + screenTask.button3 = screenTask.button(COL2, y, BUTTON_W, HEIGHT, "Start", callBack) + + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, "", libGUI.flags + RIGHT) + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) + y = y + LINE2 + local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) + tmr.disabled = true + +-- Short press EXIT handler must prompt to save scores + local function HandleEXIT(event, touchState) + if CanPopGUI() then + screenTask.buttonRet.onEvent(EVT_VIRTUAL_ENTER) + return false + else + return event + end + end + screenTask.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) +end + +do -- Prompt asking to save scores and exit task window + local x0 = (LCD_W - PROMPT_W) / 2 + local y0 = (LCD_H - PROMPT_H) / 2 + local LEFT = x0 + PROMPT_M + local RGT = x0 + PROMPT_W - PROMPT_M + local TOP = y0 + PROMPT_M + local BOTTOM = y0 + PROMPT_H - PROMPT_M + + function promptSaveScores.fullScreenRefresh() + lcd.drawFilledRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary2) + lcd.drawRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary1, 3) + end + + promptSaveScores.label(x0, TOP, PROMPT_W, HEIGHT, "Save scores?", libGUI.flags + CENTER) + + local function callBack(button) + if button == promptSaveScores.buttonYes then + local scoreFile = io.open(SCORE_FILE, "a") + if scoreFile then + io.write(scoreFile, string.format("%s,%s", model.getInfo().name, screenTask.title)) + + local now = getDateTime() + io.write(scoreFile, string.format(",%04i-%02i-%02i", now.year, now.mon, now.day)) + io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) + io.write(scoreFile, string.format(",s,%i", taskScores)) + io.write(scoreFile, string.format(",%i", totalScore)) + + for i = 1, #scores do + io.write(scoreFile, string.format(",%i", scores[i])) + end + + io.write(scoreFile, "\n") + io.close(scoreFile) + end + end + + -- Dismiss prompt and return to menu + screenTask.dismissPrompt() + screenTask.dismiss() + end -- callBack(...) + + promptSaveScores.buttonYes = promptSaveScores.button(LEFT, BOTTOM - HEIGHT, BUTTON_W, HEIGHT, "Yes", callBack) + promptSaveScores.button(RGT - BUTTON_W, BOTTOM - HEIGHT, BUTTON_W, HEIGHT, "No", callBack) + +end + +do -- Setup score browser screen + local RECORD_H = 58 -- Height of a record on the screen + local records -- Score records + local firstRecord -- First record on the screen + local scoreFile -- File handle + local pos -- Read position in file + local firstRecordTouch -- First record at the start of touch slide + + -- Read a line of a log file + local function ReadLine(scoreFile, pos) + if scoreFile and pos then + io.seek(scoreFile, pos) + local str = io.read(scoreFile, 100) + local endPos = string.find(str, "\n") + + if endPos then + pos = pos + endPos + str = string.sub(str, 1, endPos - 1) + return pos, str + end + end + + -- No "\n" was found; return nothing + return 0, "" + end -- ReadLine() + + -- Read a line a split comma separated fields + local function ParseLineData(str) + local i = 0 + local record = { } + record.scores = { } + + for field in string.gmatch(str, "[^,]+") do + i = i + 1 + + if i == 1 then + record.planeName = field + elseif i == 2 then + record.taskName = field + elseif i == 3 then + record.dateStr = field + elseif i == 4 then + record.timeStr = field + elseif i == 5 then + record.unitStr = field + elseif i == 6 then + record.taskScores = tonumber(field) + elseif i == 7 then + record.totalScore = tonumber(field) + else + record.scores[#record.scores + 1] = tonumber(field) + end + end + + if record.totalScore then + records[#records + 1] = record + end + end -- ReadLineData() + + local function DrawRecord(i, r) + local top = 40 + i * RECORD_H + local left = 200 + local w = (LCD_W - left - 10) / 3 + local record = records[r] + + if not record then + return + end + + if r % 2 == 0 then + lcd.drawFilledRectangle(0, top, LCD_W, RECORD_H, COLOR_THEME_SECONDARY2) + end + + lcd.drawText(10, top + 6, record.taskName, BOLD) + lcd.drawText(10, top + 24, record.dateStr .. " " .. record.timeStr, SMLSIZE) + lcd.drawText(10, top + 36, record.planeName, SMLSIZE) + + local x = left + local y = top + 6 + + for j = 1, math.min(5, record.taskScores) do + lcd.drawText(x, y, j .. ".") + + if j > #record.scores then + lcd.drawText(x + 18, y, "- - -") + elseif record.unitStr == "s" then + lcd.drawTimer(x + 18, y, record.scores[j]) + else + lcd.drawText(x + 18, y, record.scores[j] .. record.unitStr) + end + + if j == 3 then + x = left + y = top + 30 + else + x = x + w + end + end + + lcd.drawText(left + 2 * w, top + 30, "Total: " .. record.totalScore .. record.unitStr) + end -- DrawRecord + + function menuScores.run(event, touchState) + local color + local PROMPT_W = 300 + local PROMPT_H = 200 + + if not event then + return libGUI.widgetRefresh() + end + + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, "Score Card", bit32.bor(DBLSIZE, colors.primary2)) + + -- Date + local now = getDateTime() + local str = string.format("%02i:%02i", now.hour, now.min) + lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) + + if soarGlobals.battery == 0 then + color = COLOR_THEME_DISABLED + else + color = colors.primary2 + end + + str = string.format("%1.1fV", soarGlobals.battery) + lcd.drawText(LCD_W - 140, 6, str, RIGHT + MIDSIZE + color) + + -- Return button + lcd.drawFilledRectangle(LCD_W - 74, 6, 28, 28, COLOR_THEME_SECONDARY1) + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, colors.primary2) + + for i = -1, 1 do + lcd.drawLine(LCD_W - 60 + i, 12, LCD_W - 60 + i, 30, SOLID, colors.primary2) + end + + for i = 0, 3 do + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, colors.primary2) + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, colors.primary2) + end + + -- Minimize button + lcd.drawFilledRectangle(LCD_W - 34, 6, 28, 28, COLOR_THEME_SECONDARY1) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) + + if event ~= EVT_TOUCH_SLIDE then + firstRecordTouch = nil + end + + if event == EVT_VIRTUAL_EXIT then + firstRecord = nil + return PopGUI() + elseif event == EVT_TOUCH_TAP then + local x, y = touchState.x, touchState.y + + if 6 <= y and y <= 34 then + if LCD_W - 74 <= x and x <= LCD_W - 40 then + firstRecord = nil + return PopGUI() + elseif x >= LCD_W - 34 then + lcd.exitFullScreen() + end + end + end + + if firstRecord then + if event == EVT_VIRTUAL_PREV then + firstRecord = math.max(1, firstRecord - 1) + elseif event == EVT_VIRTUAL_NEXT then + firstRecord = math.max(1, math.min(#records - 3, firstRecord + 1)) + elseif event == EVT_TOUCH_SLIDE then + if not firstRecordTouch then + firstRecordTouch = firstRecord + end + local delta = math.floor((touchState.startY - touchState.y) / RECORD_H + 0.5) + firstRecord = math.max(1, math.min(#records - 3, firstRecordTouch + delta)) + end + + for i = 0, 3 do + local r = i + firstRecord + DrawRecord(i, r) + end + + else -- Read score records + lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) + + if not scoreFile then + scoreFile = io.open(SCORE_FILE, "r") + pos = 0 + if scoreFile then + records = { } + end + end + + if scoreFile then + for i = 1, 10 do + local str + pos, str = ReadLine(scoreFile, pos) + ParseLineData(str) + if pos == 0 then + io.close(scoreFile) + scoreFile = nil + firstRecord = math.max(1, #records - 3) + + if #records == 0 then + firstRecord = nil + end + + break + end + end + end + end + end -- run(...) +end + +-- Initialize stuff +SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua new file mode 100644 index 00000000..d2e5f60d --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/f5J.lua @@ -0,0 +1,417 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K score keeper, loadable component -- +-- -- +-- Author: Frankie Arzu/ Jesper Frickmann -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors + +-- GUIs for the different screens and popups +local screenTask = libGUI.newGUI() + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W) / 2 +local BOT_ROW = LCD_H - 60 + +-- Constants +local LS_ALT = 0 -- LS1 allowing altitude calls +local LS_ALT10 = 7 -- LS8 for altitude calls every 10 sec. + +local LS_TRIGGER = 8 -- LS9 +local LS_ARM = 22 --LS23 + +local GV_FLT_TMR = 8 -- GV8 for the flight timer +local FM_LAUNCH = 2 -- Launch/motor flight mode + +-- Program states +local STATE_INITIAL = 0 -- Set flight time before the flight +local STATE_MOTOR = 1 -- Motor running +local STATE_GLIDE = 2 -- Gliding +local STATE_LANDINGPTS = 3 -- Landed, input landing points +local STATE_STARTHEIGHT = 4 -- Input start height +local STATE_TIME = 5 -- Input flight time +local STATE_SAVE = 6 -- Ready to save +local state -- Current program state + +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevFt -- Previous value of flight timer +local prevArm -- Previous value of Arm +local prevTrig = false -- Previous vakue of Trigger +local prevMt -- Previous Motor Time + +-- Other common variables +--local counts = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45 } -- Flight timer countdown +--local countIndex -- Index of timer count + +local flightTimer -- Flight timer +local motorTimer -- Motor Timer + +local callAlt = false +local nextCall = 0 + +local prevCnt = 0 + +local startHeight = 0 +local offTime = 0 -- Motor Off time after Initial Climb +local landingPts = 0 + + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F5J Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + print("GotoState:" .. newState) + + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state == STATE_INITIAL then + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + screenTask.labelInfo.title = "INITIAL" + screenTask.labelTimer0.title = "Target:" + screenTask.locked = false + + elseif state == STATE_MOTOR then + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + screenTask.labelInfo.title = "Motor ON" + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + + elseif state == STATE_GLIDE then + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + screenTask.labelInfo.title = "Soaring .." + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + + elseif state == STATE_LANDINGPTS then + screenTask.labelInfo.title = "Landed. Launch Alt =" .. startHeight + elseif state == STATE_TIME then + screenTask.labelInfo.title = "TODO:Enter Time/Landing" + elseif state == STATE_SAVE then + screenTask.labelInfo.title = "TODO: Save Data" + end + + -- Configure "button3" + --screenTask.button3.disabled = false + --screenTask.button3.title = "Button3" + + -- Configure info text label + --screenTask.labelInfo.title = " Info Label" +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName) + screenTask.title = taskName +end -- SetupTask(...) + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +local function TargetTime() + return model.getTimer(0).start +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + --countIndex = #counts + --while countIndex > 1 and counts[countIndex] >= targetTime do + -- countIndex = countIndex - 1 + --end + + -- Set flight timer + model.setTimer(0, { start = targetTime, value = targetTime }) + flightTimer = targetTime + prevFt = targetTime + + -- Set Motor Timer + model.setTimer(1, { start = 0, value = 0 }) + + landingPts = 0 + startHeight = 100 -- default if no Alt + + GotoState(STATE_INITIAL) +end -- InitializeFlight() + +local function playMotorTime(motorTimer) + local mt = motorTimer.value -- Current motor timer value + local sayt -- Timer value to announce (we don't have time to say "twenty-something") + + local cnt + if mt <= 20 then + cnt = 5; sayt = mt + elseif mt < 30 then + cnt = 1; sayt = mt - 20 + else + cnt = 1; sayt = mt + end + + if math.floor(prevMt / cnt) < math.floor(mt / cnt) then + playNumber(sayt, 0) + end + + prevMt = mt +end -- playMotorTime + +local function playFlightTimer(flightTimer) + local ft = flightTimer.value + + -- Count down flight time + local cnt + if ft > 120 then + cnt = 60 + elseif ft > 60 then + cnt = 15 + elseif ft > 10 then + cnt = 5 + else + cnt = 1 + end + + if math.ceil(prevFt / cnt) > math.ceil(ft / cnt) then + if ft > 10 then + playDuration(ft, 0) + elseif ft > 0 then + playNumber(ft, 0) + end + end + + prevFt = ft +end -- Play FlightTimer + +local function inAltitudeWindow() + if offTime == 0 then -- no longer in 10s window + return false + end + + -- 10 sec. count after motor off + local cnt = math.floor((getTime() - offTime) / 100) + + if cnt > prevCnt then + prevCnt = cnt + + if cnt >= 10 then + offTime = 0 -- No more counts + + -- Time to record start height + local alt = getValue("Alt+") + if alt > 0 then + startHeight = alt + end + + -- Call launch height + if callAlt then + playNumber(alt, UNIT_METERS) + else + playNumber(cnt, 0) + end + else + playNumber(cnt, 0) + end + end + + return true +end -- inAltitudeWindow + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + + local motorOn = (flightMode == FM_LAUNCH) -- Motor running + local armedNow = getLogicalSwitchValue(LS_ARM) + local triggerNow = getLogicalSwitchValue(LS_TRIGGER) + + prevArm, armedNow = armedNow, armedNow and not prevArm + prevTrig, triggerNow = triggerNow, triggerNow and not prevTrig + + callAlt = (getLogicalSwitchValue(LS_ALT10)) -- Call alt every 10 sec. + + flightTimer = model.getTimer(0) -- Current flight timer value + motorTimer = model.getTimer(1) -- Current motor timer value + + if armedNow and state ~= STATE_INITIAL then + InitializeFlight() + end + + if state == STATE_INITIAL then + -- Reset altitude if the motor was armed now + if armedNow then + ResetAlt() + screenTask.labelInfo.title = "MOTOR ARMED" + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + end + + if motorOn then + GotoState(STATE_MOTOR) + -- Reset MotorTime Call and Alt Window Time + prevMt = flightTimer.value + offTime = 0 + end + elseif state == STATE_MOTOR then + playMotorTime(motorTimer) + + if not motorOn then -- Motor stopped + if offTime == 0 then + -- start 10 sec. Alt Window to record start height + offTime = now; prevCnt = 1 + end + + if triggerNow then -- Trigger switch released + prevFt = flightTimer.value + end + GotoState(STATE_GLIDE) + end + elseif state == STATE_GLIDE then + playFlightTimer(flightTimer) + + if (not inAltitudeWindow()) then + -- Call altitude every 10 sec. + if callAlt and now > nextCall then + playNumber(getValue("Alt"), UNIT_METERS) + nextCall = now + 1000 + end + end + + if triggerNow then + -- Stop timer and record scores + GotoState(STATE_LANDINGPTS) + playTone(880, 1000, 0) + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + model.setTimer(0, { value = flightTimer.start - flightTimer.value }) + playDuration(flightTimer.start - flightTimer.value) + end + -- STATE_GLIDE + elseif state == STATE_LANDINGPTS then + if triggerNow then + GotoState(STATE_TIME) + end + elseif state == STATE_TIME then + if triggerNow then + GotoState(STATE_SAVE) + end + elseif state == STATE_SAVE then + if triggerNow then + InitializeFlight() + end + end + + -- Motor restart; score a zero + if (state == STATE_GLIDE or state == STATE_LANDINGPTS) and motorOn then + state = STATE_SAVE + model.setTimer(0, { value = 0 }) + startHeight = 0 + end +end -- background() + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = (widget.zone.w / 2) - 198 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + -- Draw timers + local blink = 0 + local y = 1 + + local tmr = model.getTimer(0).value -- Flight + if tmr < 0 and state > STATE_GLIDE then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + tmr = model.getTimer(1).value -- Motor + lcd.drawText(COL3, y + 10, "Motor:", colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) + y = y + 2 * dy + lcd.drawText(COL1, y, screenTask.labelInfo.title, colors.primary1 + DBLSIZE) +end -- widgetRefresh() + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + --screenTask.run(event,touchState + libGUI.widgetRefresh() +end -- refresh(...) + +local function SetupScreenTask() + print("SetupScreenTask:Begin") + local y + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, " Info ", libGUI.flags + RIGHT) + + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) + y = y + LINE2 + local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) + tmr.disabled = true + print("SetupScreenTask:End") +end + + +-- Initialize stuff +SetupScreenTask() +SetupTask("10 Min Window") +InitializeFlight() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua new file mode 100644 index 00000000..97bdc70e --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/graph.lua @@ -0,0 +1,586 @@ +--------------------------------------------------------------------------- +-- SoarETX graph of log data -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-28 -- +-- Version: 1.0.1 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- +local widget, soarGlobals = ... + +local libGUI = loadGUI() +libGUI.flags = 0 +local colors = libGUI.colors +local title = "Graph" + +-- Screen drawing constants +local LCD_W2 = LCD_W / 2 +local HEADER = 40 +local TOP = 50 +local BOTTOM = LCD_H - 18 +local LINE = 40 +local HEIGHT = 28 +local LFT = 30 +local WIDTH = 60 +local W1 = 0.4 * (LCD_W - 3 * LFT) +local W2 = (LCD_W - 3 * LFT) - W1 +local COL2 = W1 + 2 * LFT +local PLOT_W = LCD_W - 3 * LFT - WIDTH +local PLOT_H = BOTTOM - TOP +local RGT = LFT + PLOT_W +local MARGIN = 10 +local BUTTON_X = RGT + MARGIN +local BUTTON_W = LCD_W - BUTTON_X - MARGIN + +-- Other constants +local FMAX = 1E38 +local DEFAULT_PLOT = "Alt" +local FIRST_EXCLUDED = "Rud" +do + local lang = getGeneralSettings().language + if lang == "CZ" then + FIRST_EXCLUDED = "Smer" + elseif lang == "DE" then + FIRST_EXCLUDED = "Sei" + elseif lang == "FR" or lang == "IT" then + FIRST_EXCLUDED = "Dir" + elseif lang == "PL" then + FIRST_EXCLUDED = "SK" + elseif lang == "PT" then + FIRST_EXCLUDED = "Lem" + elseif lang == "SE" then + FIRST_EXCLUDED = "Rod" + end +end + +-- Variables +local gui +local guiFile +local guiPause +local guiGraph +local menu1 +local menu2 +local buildingTree +local fileTree +local fileCount +local getNextFileName +local fileName +local data +local refreshDates +local lines +local cursor +local xMin +local xScale +local y0 +local yScale + +------------------------------- Reading data ------------------------------ + +local function timeSerial(str) + local hr = string.sub(str, 1, 2) + local mn = string.sub(str, 4, 5) + local sc = string.sub(str, 7, 12) + return 3600 * hr + 60 * mn + sc +end + +local function buildFileTree() + if not fileTree then + guiPause.title = "READING..." + gui = guiPause + fileTree = { } + fileCount = 0 + getNextFileName = dir("/LOGS") + fileName = getNextFileName() + end + + while fileName do + -- If there are many files, then we may run out of CPU instructions + if getUsage() > 90 then + return + end + + if string.len(fileName) > 23 and string.sub(fileName, -4) == ".csv" then + local dateStr = string.sub(fileName, -21, -12) + local nameStr = string.sub(fileName, -10, -9) .. ":" .. string.sub(fileName, -8, -7) .. ":" .. + string.sub(fileName, -6, -5) .. " " .. string.sub(fileName, 1, -23) + + if not fileTree[dateStr] then + fileTree[dateStr] = { } + fileCount = fileCount + 1 + end + + fileTree[dateStr][nameStr] = fileName + end + + fileName = getNextFileName() + end + + if getUsage() > 20 then + return + end + + getNextFileName = nil + fileName = nil + + if fileCount == 0 then + guiPause.title = "NO LOG FILES" + gui = guiPause + headers = nil + data = { } + else + refreshDates() + gui = guiFile + end + + buildingTree = false +end + +local function readLines(fileName) + -- data[2] = min values, data[3] = max values + data = { { }, { FMAX }, { -FMAX } } + + if not fileName then + return + end + + fileName = "/LOGS/" .. fileName + local fileStat = fstat(fileName) + + if not fileStat then + return + end + + local l = string.len(DEFAULT_PLOT) + local plotIdx = 2 + local logFile = io.open(fileName, "r") + local logString = io.read(logFile, fileStat.size) + io.close(logFile) + lines = { } + + local i = 0 + for line in string.gmatch(logString, "[^\n]+") do + i = i + 1 + lines[i] = line + end + + if #lines < 3 then + return + end + + local headers = { } + i = -1 + for field in string.gmatch(lines[1], "[^,]+") do + i = i + 1 + if i >= 1 then + headers[i] = field + end + end + + for i = 2, #headers do + if string.sub(headers[i], 1, l) == DEFAULT_PLOT then + plotIdx = i + end + if headers[i] == FIRST_EXCLUDED then + break + end + data[1][i - 1] = headers[i] + data[2][i] = FMAX + data[3][i] = -FMAX + end + + local ddp = guiGraph.ddPlot + if #data[1] == 0 then + ddp.disabled = true + else + ddp.disabled = false + ddp.items = data[1] + if ddp.selected > #data[1] then + ddp.selected = plotIdx - 1 + end + end + gui = guiGraph +end + +local function readData() + local plotIdxLast = #data[1] + 1 + + for i = #data - 1, #lines do + if getUsage() > 90 then + return + end + local j = -1 + local y + local record = { } + for field in string.gmatch(lines[i], "[^,]+") do + j = j + 1 + if j > 0 then + if j > plotIdxLast then + break + elseif j > 1 then + y = tonumber(field) + else + y = timeSerial(field) + end + record[j] = y + data[2][j] = math.min(y, data[2][j]) + data[3][j] = math.max(y, data[3][j]) + end + end + data[i + 2] = record + end + lines = nil + cursor = math.ceil((#data + 3) / 2) +end + +local function readSelected() + local date = menu1.items[menu1.selected] + local name = menu2.items[menu2.selected] + guiGraph.title = name + fileName = fileTree[date][name] + readLines(fileName) +end + +-------------------------------- Setup GUI -------------------------------- + +-- Common GUI setup +local function setupGUI(title) + local gui = libGUI.newGUI() + gui.title = title + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, gui.title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Extra drawing + gui.drawMore() + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + return gui +end + +-- GUI to show if there are no log files +guiPause = setupGUI("Graph") +guiPause.title = "" + +function guiPause.drawMore() + lcd.drawText(LCD_W / 2, LCD_H / 2, guiPause.title, XXLSIZE + CENTER + VCENTER + colors.primary1) +end + +-- GUI for selecting log file +do + guiFile = setupGUI("Select a log file") + + function guiFile.drawMore() + lcd.drawLine(COL2 - LFT / 2, TOP, COL2 - LFT / 2, BOTTOM, SOLID, colors.primary1) + end + + local function refreshTimes() + local date = menu1.items[menu1.selected] + local times + if fileTree[date] then + times = { } + for t in pairs(fileTree[date]) do + times[#times + 1] = t + end + table.sort(times) + else + times = { "No files" } + end + menu2.items = times + menu2.selected = 1 + end + + function refreshDates() + local dates = { } + for d in pairs(fileTree) do + dates[#dates + 1] = d + end + table.sort(dates) + menu1.items = dates + refreshTimes() + end + + local function onMenu1() + refreshTimes() + guiFile.onEvent(EVT_VIRTUAL_NEXT) + guiFile.onEvent(EVT_VIRTUAL_ENTER) + end + + menu1 = guiFile.menu(LFT, TOP, W1, BOTTOM - TOP, nil, onMenu1) + + local function onMenu2() + readSelected() + guiFile.onEvent(EVT_VIRTUAL_PREV) + guiFile.onEvent(EVT_VIRTUAL_ENTER) + end + + menu2 = guiFile.menu(COL2, TOP, W2, BOTTOM - TOP, nil, onMenu2) -- Add graph function + + guiFile.onEvent(EVT_VIRTUAL_NEXT) + guiFile.onEvent(EVT_VIRTUAL_ENTER) +end -- Setup guiFile + +-- GUI for plotting the graph +do + guiGraph = setupGUI("") + local toggleCursor + + local y = TOP + guiGraph.ddPlot = guiGraph.dropDown(BUTTON_X, y, BUTTON_W, HEIGHT, { "1", "2", "3", "4", "5", "6", "- - -" }, 7, nil, CENTER) + + y = y + LINE + guiGraph.button(BUTTON_X, y, BUTTON_W, HEIGHT, "New file", function() gui = guiFile end) + + y = y + LINE + + local function moveCursor(d) + cursor = cursor + d + if cursor > #data then + cursor = 4 + elseif cursor < 4 then + cursor = #data + end + end + + -- Trap events with prompt when cursor is active + local trapCursor = { + run = function(event, touchState) + if touchState then + local tx, ty = touchState.x - LFT, touchState.y + if 0 <= tx and tx <= PLOT_W and TOP <= ty and ty <= TOP + PLOT_H then + local x = tx / xScale + xMin + local y = (y0 - ty) / yScale + -- Find the nearest x-values + local i1 = 4 + local i2 = #data + while i2 - i1 > 1 do + local i = math.floor((i1 + i2) / 2) + if data[i][1] <= x then + i1 = i + else + i2 = i + end + end + -- Search for nearest point within x-window + local ddMin = FMAX + local plotIdx = guiGraph.ddPlot.selected + 1 + for i = math.max(4, i1 - 4), math.min(#data, i2 + 4) do + x = LFT + xScale * (data[i][1] - xMin) + y = y0 - yScale * data[i][plotIdx] + local dd = (tx - x) ^ 2 + (ty - y) ^ 2 + if dd < ddMin then + ddMin = dd + cursor = i + end + end + elseif event == EVT_TOUCH_TAP then + toggleCursor.onEvent(EVT_VIRTUAL_ENTER) + end + elseif event == EVT_VIRTUAL_ENTER then + toggleCursor.onEvent(event) + elseif event == EVT_VIRTUAL_PREV then + moveCursor(-1) + elseif event == EVT_VIRTUAL_NEXT then + moveCursor(1) + end + end + } + + local function onToggleCursor() + if toggleCursor.value then + guiGraph.showPrompt(trapCursor) + else + guiGraph.dismissPrompt() + end + end + + toggleCursor = guiGraph.toggleButton(BUTTON_X, y, BUTTON_W, HEIGHT, "Cursor", false, onToggleCursor) + + local function onArrows(d) + local s = menu2.selected + d + if s < 1 then + s = #menu2.items + elseif s > #menu2.items then + s = 1 + end + menu2.selected = s + readSelected() + end + + y = BOTTOM - HEIGHT + local w = (BUTTON_W - MARGIN) / 2 + guiGraph.button(BUTTON_X, y, w, HEIGHT, CHAR_LEFT, function() onArrows(-1) end) + guiGraph.button(BUTTON_X + MARGIN + w, y, w, HEIGHT, CHAR_RIGHT, function() onArrows(1) end) + + function guiGraph.drawMore() + local plotIdx = guiGraph.ddPlot.selected + 1 + + -- Background + lcd.drawFilledRectangle(LFT, TOP, PLOT_W, PLOT_H, colors.primary2) + lcd.drawRectangle(LFT, TOP, PLOT_W, PLOT_H, COLOR_THEME_SECONDARY2) + + if lines then + local txt = "READING DATA" + local flags = DBLSIZE + CENTER + VCENTER + colors.primary1 + lcd.drawText(LFT + PLOT_W / 2, TOP + PLOT_H / 2, txt, DBLSIZE + CENTER + VCENTER + colors.primary1) + readData() + return + elseif #data < 6 or #data[1] == 0 then + local txt = "NO DATA IN THIS FILE" + local flags = DBLSIZE + VCENTER + CENTER + colors.primary1 + lcd.drawText(LFT + PLOT_W / 2, TOP + PLOT_H / 2, txt, flags) + return + end + + -- Time scale + xMin = data[2][1] + local xRange = math.max(60, data[3][1] - xMin) + xScale = PLOT_W / xRange + -- Y-scale + local yRange = data[3][plotIdx] - data[2][plotIdx] + local mag = math.max(-2, math.floor(math.log(yRange, 10))) + local yTick + local r = yRange / 10^mag + if r > 6 then + yTick = 2 * 10^mag + elseif r > 3 then + yTick = 1 * 10^mag + elseif r > 2.4 then + yTick = 0.5 * 10^mag + elseif r > 1.2 then + yTick = 0.4 * 10^mag + else + yTick = 0.2 * 10^mag + end + yTick = math.max(0.01, yTick) + local yMin = yTick * math.floor(data[2][plotIdx] / yTick) + local yMax = yTick * math.ceil(data[3][plotIdx] / yTick) + if yMin == yMax then + yMin = yMin - yTick + yMax = yMax + yTick + end + yScale = PLOT_H / (yMax - yMin) + y0 = BOTTOM + yScale * yMin + -- Flags for number precision + local fmt + if yTick < 0.1 then + fmt = "%1.2f" + elseif yTick < 1 then + fmt = "%2.1f" + else + fmt = "%3i" + end + -- Lines + for x = 0, xRange, 60 do + local xx = LFT + xScale * x + lcd.drawLine(xx, TOP, xx, BOTTOM, DOTTED, COLOR_THEME_SECONDARY2) + if x > 0 then + lcd.drawNumber(xx, BOTTOM, x / 60, CENTER + colors.primary3) + end + end + for y = yMin, yMax, yTick do + local yy = y0 - yScale * y + if math.abs(y) < 1E-12 then + lcd.drawLine(LFT, yy, RGT, yy, SOLID, COLOR_THEME_SECONDARY2) + else + lcd.drawLine(LFT, yy, RGT, yy, DOTTED, COLOR_THEME_SECONDARY2) + end + lcd.drawText(LFT, yy, string.format(fmt, y), VCENTER + RIGHT + colors.primary3) + end + -- Graph curve + local x1 = LFT + xScale * (data[4][1] - xMin) + local y1 = y0 - yScale * data[4][plotIdx] + for i = 5, #data do + local x2 = LFT + xScale * (data[i][1] - xMin) + local y2 = y0 - yScale * data[i][plotIdx] + lcd.drawLine(x1, y1, x2, y2, SOLID, COLOR_THEME_SECONDARY1, 3) + x1, y1 = x2, y2 + end + -- Cursor point + if toggleCursor.value then + local delta + local flags = CENTER + COLOR_THEME_SECONDARY1 + x1 = LFT + xScale * (data[cursor][1] - xMin) + y1 = y0 - yScale * data[cursor][plotIdx] + lcd.drawFilledCircle(x1, y1, 5, colors.active) + lcd.drawCircle(x1, y1, 4, COLOR_THEME_SECONDARY1) + lcd.drawCircle(x1, y1, 5, COLOR_THEME_SECONDARY1) + -- Slope + if cursor == 4 then + delta = (data[cursor + 1][plotIdx] - data[cursor][plotIdx]) / (data[cursor + 1][1] - data[cursor][1]) + elseif cursor == #data then + delta = (data[cursor][plotIdx] - data[cursor - 1][plotIdx]) / (data[cursor][1] - data[cursor - 1][1]) + else + delta = (data[cursor + 1][plotIdx] - data[cursor - 1][plotIdx]) / (data[cursor + 1][1] - data[cursor - 1][1]) + end + -- Plot value and slope + if y1 - TOP < 24 then + y1 = y1 + 8 + elseif BOTTOM - y1 < 24 then + y1 = y1 - 56 + else + y1 = y1 - 24 + end + lcd.drawText(x1, y1, string.format("Y=" .. fmt, data[cursor][plotIdx]), flags) + lcd.drawText(x1, y1 + 24, string.format(CHAR_DELTA .. "=" .. fmt, 60 * delta), flags) + end + end + + guiGraph.onEvent(EVT_VIRTUAL_NEXT) +end -- Setup guiGraph + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + buildingTree = true + fileTree = nil +end -- background() + +function widget.refresh(event, touchState) + if not event then + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + widget.background() + return + end + + if buildingTree then + buildFileTree() + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua new file mode 100644 index 00000000..46498d46 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/mixes.lua @@ -0,0 +1,213 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K configure mixes and battery warning, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-09 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Mixes & Battery" +local modelType = "" +local fm = getFlightMode() + +-- Screen drawing constants +local LCD_W2 = LCD_W / 2 +local HEADER = 40 +local LINE = 32 +local HEIGHT = LINE - 4 +local MARGIN = 15 +local W1 = 170 +local W2 = LCD_W2 - 2 * MARGIN - W1 + +local mixes_F3K = { + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, -100, 100}, + {"Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Elevator input", 6, 20, 100}, + {"Aileron input", 7, 20, 100}, + {"Exponential", 8, 20, 100} +} + +local mixes_F3K_RE = { + {"Elevator input", 6, 20, 100}, + {"Exponential", 8, 20, 100} +} + +local mixes_F3K_FH = { + {"Elevator input", 7, 20, 100}, + {"Aileron input", 0, 10, 100}, + {"Aileron " .. CHAR_RIGHT .. " flaps", 1, 0, 100}, + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, 0, 100}, + {"Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Camber " .. CHAR_RIGHT .. " aileron", 6, 0, 200}, + {"Exponential", 8, 0, 100} +} + +local mixes_FxJ = { + {"Aileron " .. CHAR_RIGHT .. " Rudder", 2, -100, 100}, + {"Aileron Travel", 0, -100, 100}, + {"Aileron " .. CHAR_RIGHT .. " Flap", 1, -100, 100}, + {"Aileron Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " Elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Camber " .. CHAR_RIGHT .." Aileron", 6, 0, 400} +} + +local mixes_FXY = { + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, -100, 100} +} + +local mixes = mixes_F3K + +-------------------------------- Setup GUI -------------------------------- + +do + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_TRAD" then + mixes = mixes_F3K + elseif modelType == "F3K_FH" then + mixes = mixes_F3K_FH + elseif modelType == "F3K_RE" then + mixes = mixes_F3K_RE + elseif modelType == "F3J" or modelType == "F5J" then + mixes = mixes_FxJ + else + mixes = mixes_FXY + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Fligh mode + local fmIdx, fmStr = getFlightMode() + lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) + + -- Line stripes + for i = 1, 3, 2 do + lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) + end + + local bottom = HEADER + 4 * LINE + lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) + + -- Help text + local txt = "Some variables can be adjusted individually for each flight mode.\n" .. + "Therefore, select the flight mode for which you want to adjust.\n" .. + "You can change that behaviour under GLOBAL VARIABLES." + lcd.drawTextLines(MARGIN, bottom + 25, LCD_W - 2 * MARGIN, LCD_H - bottom, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Grid for items + local x, y = MARGIN, HEADER + 2 + + local function move() + if x == MARGIN then + x = x + LCD_W2 + else + x = MARGIN + y = y + LINE + end + end + + -- Add label and number element for a GV + local function addGV(label, gv, min, max) + gui.label(x, y, W1, HEIGHT, label) + + local function changeGV(delta, number) + local value = number.value + delta + value = math.max(value, min) + value = math.min(value, max) + model.setGlobalVariable(gv, fm, value) + return value + end + + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) + + function number.update() + number.value = model.getGlobalVariable(gv, fm) + end + + move() + end + + -- ADD GVs + for i, mix in ipairs(mixes) do + addGV(mix[1], mix[2], mix[3], mix[4]) + end + + -- Add battery warning + gui.label(x, y, W1, HEIGHT, "Battery warning level (V)") + + local function changeBattery(delta, bat) + local value = bat.value + delta + value = math.max(0, value) + value = math.min(200, value) + soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) + return value + end + + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) + gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) +end -- Setup GUI + +function widget.background() +end -- background() + +function widget.refresh(event, touchState) + if not event then + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + end + + fm = getFlightMode() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/name.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/name.lua new file mode 100644 index 00000000..d8c77c6c --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/name.lua @@ -0,0 +1,38 @@ +--------------------------------------------------------------------------- +-- SoarETX model name, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-08 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget = ... +local name = model.getInfo().name +local att = SMLSIZE + +for i, a in ipairs({ DBLSIZE, MIDSIZE, BOLD, 0 }) do + local w = lcd.sizeText(name, a) + if w <= widget.zone.w then + att = a + break + end +end + +att = att + VCENTER + COLOR_THEME_PRIMARY2 + +function widget.refresh(event, touchState) + lcd.drawText(0, widget.zone.h / 2, name, att) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua new file mode 100644 index 00000000..a0738913 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/outputs.lua @@ -0,0 +1,595 @@ +--------------------------------------------------------------------------- +-- SoarETX outputs configuration widget, loadable part -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-19 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui +local colors = libGUI.colors +local title = "Outputs" + +local warningPrompt = libGUI.newGUI() -- Warning prompt shown on opening +local editPrompt = libGUI.newGUI() -- Prompt asking what to edit +local channels -- List sub-GUIs for named channels +local focusNamed = 0 -- Index of sub-GUI in focus +local firstLine = 1 -- Index of sub-GUI on the first line +local editPoints = 0 -- Select what points to edit + +local N = 32 -- Highest channel number to swap +local MAXOUT = 1500 -- Maximum output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local CHAN_BASE = getFieldInfo("ch1").id - 1 -- Base of channel sources + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 10 +local TOP = 50 +local ROW = 38 +local CTR = 340 +local STEP = 10 +local SCALE = 12 +local MAXOUT = 1500 +local MINDIF = 100 + +-- Function that gives the active points for a given value of editPoints +local function activePoints(ep) + local p = { 0, 0, 0 } + if ep == 1 then + p[1] = 1 + p[2] = 1 + p[3] = 1 + elseif ep == 2 then + p[1] = -1 + p[3] = 1 + elseif ep == 3 then + p[1] = 1 + elseif ep == 4 then + p[2] = 1 + else -- 5 + p[3] = 1 + end + return p +end -- activePoints(...) + +-- Setup warning prompt +do + local PROMPT_W = 300 + local PROMPT_H = 172 + warningPrompt.x = (LCD_W - PROMPT_W) / 2 + warningPrompt.y = (LCD_H - PROMPT_H) / 2 + + function warningPrompt.fullScreenRefresh() + local txt = "Please disable the motor!\n\n" .. + "Sudden spikes may occur when channels are moved.\n\n" .. + "Press ENTER to proceed." + + warningPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) + warningPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) + warningPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) + warningPrompt.drawText(MARGIN, HEADER / 2, "W A R N I N G", DBLSIZE + VCENTER + libGUI.colors.primary2) + warningPrompt.drawTextLines(MARGIN, HEADER + MARGIN, PROMPT_W - 2 * MARGIN, PROMPT_H - 2 * MARGIN, txt) + end + + -- Make a dismiss button from a custom element + local custom = warningPrompt.custom({ }, PROMPT_W - 30, 10, 20, 20) + + function custom.draw(focused) + warningPrompt.drawRectangle(PROMPT_W - 30, 10, 20, 20, libGUI.colors.primary2) + warningPrompt.drawText(PROMPT_W - 20, 20, "X", MIDSIZE + CENTER + VCENTER + libGUI.colors.primary2) + if focused then + custom.drawFocus() + end + end + + function custom.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + gui.dismissPrompt() + end + end +end -- Warning prompt + +-- Setup prompt for selecting what to edit +do + local PROMPT_W = 280 + local PROMPT_H = 210 + local MENU_W = 75 + local MENU_H = PROMPT_H - HEADER - 2 * MARGIN + local X = { 110, 180, 250 } + local MAX_D = 20 + local t0 = 0 + local h = select(2, lcd.sizeText("", libGUI.flags)) + local menuItems = { + "Offset", + "Range", + "Lower", + "Center", + "Upper" + } + editPrompt.x = (LCD_W - PROMPT_W) / 2 + editPrompt.y = (LCD_H - PROMPT_H) / 2 + + function editPrompt.fullScreenRefresh() + if not editPrompt.editing then + editPoints = 0 + gui.dismissPrompt() + gui.onEvent(EVT_VIRTUAL_EXIT) + return + end + + editPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) + editPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) + editPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) + editPrompt.drawText(MARGIN, HEADER / 2, "Select what to edit:", DBLSIZE + VCENTER + libGUI.colors.primary2) + + local y = HEADER + MARGIN + h / 2 + + for i = 1, 5 do + local p = activePoints(i) + editPrompt.drawFilledRectangle(X[1], y - 2, X[3] - X[1], 5, libGUI.colors.primary1) + for j = 1, 3 do + if p[j] == 0 then + editPrompt.drawFilledRectangle(X[j] - 2, y - 10, 5, 20, libGUI.colors.primary1) + else + editPrompt.drawFilledCircle(X[j], y, 10, libGUI.colors.edit) + for i = -1, 1 do + editPrompt.drawCircle(X[j], y, 10 + i, libGUI.colors.active) + end + end + end + y = y + h + end + end -- fullScreenRefresh() + + local function onMenu(menu) + editPoints = menu.selected + gui.dismissPrompt() + end -- onMenu(...) + + editPrompt.menu(MARGIN, HEADER + MARGIN, MENU_W, MENU_H, menuItems, onMenu) +end -- Prompt for selecting what to edit + +-- Move output channel by swapping with previous or next; direction = -1 or +1 +local function MoveOutput(direction, channel) + local m = { } -- Channel indices + m[1] = channel.iChannel -- Channel to move + m[2] = m[1] + direction -- Neighbouring channel to swap + + -- Are we at then end? + if m[2] < 1 or m[2] > N then + playTone(3000, 100, 0, PLAY_NOW) + return + end + + local outputs = { } -- List of output tables + local mixes = { } -- List of lists of mixer tables + + -- Read channel into tables + for i = 1, 2 do + outputs[i] = model.getOutput(m[i] - 1) + + -- Read list of mixer lines + mixes[i] = { } + for j = 1, model.getMixesCount(m[i] - 1) do + mixes[i][j] = model.getMix(m[i] - 1, j - 1) + end + end + + -- Write back swapped data + for i = 1, 2 do + model.setOutput(m[i] - 1, outputs[3 - i]) + + -- Delete existing mixer lines + for j = 1, model.getMixesCount(m[i] - 1) do + model.deleteMix(m[i] - 1, 0) + end + + -- Write back mixer lines + for j, mix in pairs(mixes[3 - i]) do + model.insertMix(m[i] - 1, j - 1, mix) + end + end + + -- Swap sources for the two channels in all mixes + for i = 1, N do + local mixes = { } -- List of mixer tables + local dirty = false -- If any sources were swapped, then write back data + + -- Read mixer lines and swap sources if they match the two channels being swapped + for j = 1, model.getMixesCount(i - 1) do + mixes[j] = model.getMix(i - 1, j - 1) + if mixes[j].source == m[1] + CHAN_BASE then + dirty = true + mixes[j].source = m[2] + CHAN_BASE + elseif mixes[j].source == m[2] + CHAN_BASE then + dirty = true + mixes[j].source = m[1] + CHAN_BASE + end + end + + -- Do we have to write back data? + if dirty then + -- Delete existing mixer lines + for j = 1, model.getMixesCount(i - 1) do + model.deleteMix(i - 1, 0) + end + + -- Write new mixer lines + for j, mix in ipairs(mixes) do + model.insertMix(i - 1, j - 1, mix) + end + end + end + + -- Update channel GUI(s) on the screen + channel.iChannel = m[2] + channel.output = outputs[1] + local iNamed2 = channel.iNamed + direction + local channel2 = channels[iNamed2] + if channel2 and channel2.iChannel == m[2] then + -- Swapping two named channels! + channel2.iChannel = m[1] + channel2.output = outputs[2] + channels[channel.iNamed], channels[iNamed2] = channel2, channel + channel.iNamed, channel2.iNamed = iNamed2, channel.iNamed + gui.moveFocused(direction) + end +end -- MoveOutput() + +local function init() + -- Start building GUI from scratch + gui = libGUI.newGUI() + gui.showPrompt(warningPrompt) + + function gui.fullScreenRefresh() + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(MARGIN, HEADER / 2 - 2, "Configure Outputs", DBLSIZE + VCENTER + colors.primary2) + + -- Row background + for i = 0, 6 do + local y = HEADER + i * ROW + if i % 2 == 1 then + lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY2) + else + lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY3) + end + end + + -- Adjust scroll for channels + if focusNamed > 0 then + if focusNamed < firstLine then + firstLine = focusNamed + elseif firstLine + 5 < focusNamed then + firstLine = focusNamed - 5 + end + end + focusNamed = 0 + + -- Draw vertical reference lines + for i = -6, 6 do + local x = CTR - i * MAXOUT / (SCALE * 6) + 2 + lcd.drawLine(x, HEADER, x, HEADER + 6 * ROW, DOTTED, FORCE, COLOR_THEME_DISABLED) + end + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Build the list of named channels, each in their own movable GUI + do + local HEIGHT = ROW - 8 + local iNamed = 0 + channels = { } + + for iChannel = 1, N do + local output = model.getOutput(iChannel - 1) + + if output and output.name ~= "" then + local channel = gui.gui(2, LCD_H, LCD_W - 4, ROW - 4) + local d0 + + iNamed = iNamed + 1 + channels[iNamed] = channel + channel.iNamed = iNamed + channel.iChannel = iChannel + channel.output = output + + -- Hack the sub-GUI's draw function to do a few extra things + local draw = channel.draw + function channel.draw(focused) + -- Needed to adjust scroll in fullScreenRefresh() + if focused then + focusNamed = channel.iNamed + end + -- If channel is not visible, place it outside the screen to avoid receiving touch events + if channel.iNamed < firstLine or channel.iNamed > firstLine + 5 then + channel.y = LCD_H + else + channel.y = HEADER + (channel.iNamed - firstLine) * ROW + 2 + draw(focused) + end + end + + -- Hack the sub-GUI's onEvent function to do finger scrolling + local onEvent = channel.onEvent + function channel.onEvent(event, touchState) + if event == EVT_TOUCH_SLIDE and not channel.editing then + firstLine = math.floor(channel.iNamed - (touchState.y - HEADER - ROW / 2) / ROW + 0.5) + firstLine = math.min(firstLine, #channels - 5, channel.iNamed) + firstLine = math.max(firstLine, 1, channel.iNamed - 5) + else + onEvent(event, touchState) + end + end -- onEvent(...) + + -- Custom element for changing output channel (and moving all mixer lines etc.) + local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) + + function nbrChannel.draw(focused) + local fg = libGUI.colors.primary1 + if focused then + nbrChannel.drawFocus() + if channel.editing then + fg = libGUI.colors.primary2 + channel.drawFilledRectangle(2, 2, 30, HEIGHT, libGUI.colors.edit) + end + end + channel.drawNumber(30, HEIGHT / 2 + 2, channel.iChannel, libGUI.flags + VCENTER + RIGHT + fg) + end + + function nbrChannel.onEvent(event, touchState) + if channel.editing then + if libGUI.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + channel.editing = false + elseif event == EVT_VIRTUAL_INC then + MoveOutput(1, channel) + elseif event == EVT_VIRTUAL_DEC then + MoveOutput(-1, channel) + elseif event == EVT_TOUCH_FIRST then + d0 = 0 + elseif event == EVT_TOUCH_SLIDE then + local d = math.floor((touchState.y - touchState.startY) / ROW + 0.5) + if d ~= d0 then + MoveOutput(d - d0, channel) + d0 = d + end + end + elseif event == EVT_VIRTUAL_ENTER then + channel.editing = true + end + end -- onEvent(...) + + -- Label for channel name + local lblName = channel.label(32, 2, 140, HEIGHT, ". " .. channel.output.name) + + -- Custom element to invert output direction + local revert = channel.custom({ }, 172, 2, 30, HEIGHT) + + function revert.draw(focused) + local y = HEIGHT / 2 + 3 + if channel.output.revert == 1 then + channel.drawFilledRectangle(178, y - 1, 19, 3, colors.primary1) + for x = 177, 180 do + channel.drawLine(x, y, x + 8, y - 8, SOLID, colors.primary1) + channel.drawLine(x, y, x + 8, y + 8, SOLID, colors.primary1) + end + else + channel.drawFilledRectangle(177, y - 1, 19, 3, colors.primary1) + for x = 194, 197 do + channel.drawLine(x, y, x - 8, y - 8, SOLID, colors.primary1) + channel.drawLine(x, y, x - 8, y + 8, SOLID, colors.primary1) + end + end + + function revert.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + channel.output.revert = 1 - channel.output.revert + model.setOutput(channel.iChannel - 1, channel.output) + end + end + + if focused then + revert.drawFocus() + end + end + + -- Custom element to adjust center and end points + do + local interval = channel.custom({ }, 210, 2, 264, HEIGHT) + interval.editable = true + local flags = SMLSIZE + CENTER + INVERS + libGUI.colors.primary2 + local x + local y = HEIGHT / 2 + 2 + local yLbl = y - 12 - select(2, lcd.sizeText("", flags)) + local iScroll = 0 + + function interval.draw(focused) + local output = channel.output + local p = { 0, 0, 0 } + local colorBar = libGUI.colors.primary3 + local colorDot = libGUI.colors.primary2 + local colorDotBorder = libGUI.colors.primary3 + + x = { + CTR + output.min / SCALE, + CTR + output.offset / SCALE, + CTR + output.max / SCALE + } + if focused then + colorDotBorder = libGUI.colors.active + if channel.editing then + -- Draw value labels + channel.drawNumber(x[1], yLbl, 0.1 * output.min, flags) + channel.drawNumber(x[2], yLbl, 0.1 * output.offset, flags) + channel.drawNumber(x[3], yLbl, 0.1 * output.max, flags) + colorBar = libGUI.colors.primary1 + colorDot = libGUI.colors.edit + p = activePoints(editPoints) + else + interval.drawFocus() + end + end + -- Draw figure + channel.drawFilledRectangle(x[1], y - 2, x[3] - x[1], 5, colorBar) + for j = 1, 3 do + if p[j] == 0 then + channel.drawFilledRectangle(x[j] - 1, y - 10, 3, 20, colorBar) + else + channel.drawFilledCircle(x[j], y, 10, colorDot) + for i = -1, 1 do + channel.drawCircle(x[j], y, 10 + i, colorDotBorder) + end + end + end + -- Draw position indicators + local outX = getValue(CHAN_BASE + channel.iChannel) + if outX >= 0 then + outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 + else + outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 + end + outX = CTR + outX / SCALE + channel.drawFilledTriangle(outX, y - 3, outX - 3, y - 9, outX + 3, y - 9, colorBar) + channel.drawLine(outX, y - 2, outX, y + 2, SOLID, colorBar) + channel.drawFilledTriangle(outX, y + 3, outX - 3, y + 9, outX + 3, y + 9, colorBar) + end -- draw(...) + + local RR = 14 ^ 2 + + local function ptCovers(p, q) + local ap = activePoints(editPoints) + + for i = 1, 3 do + if ap[i] ~= 0 and (x[i] - p) ^ 2 + (y - q) ^ 2 <= RR then + return i + end + end + return 0 + end -- ptCovers(...) + + local function adjustPoints(d) + local output = channel.output + local p = activePoints(editPoints) + local min = output.min + local ctr = output.offset + local max = output.max + + -- Check limits + if p[1] == -1 then + d = math.min(d, math.max(0, MAXOUT + min)) + elseif p[1] == 1 then + d = math.max(d, math.min(0, -(MAXOUT + min))) + end + + if p[2] - p[1] == 1 then + d = math.max(d, math.min(0, MINDIF + min - ctr)) + elseif p[2] - p[1] == -1 then + d = math.min(d, math.max(0, ctr - min - MINDIF)) + end + + if p[3] - p[2] == 1 then + d = math.max(d, math.min(0, MINDIF + ctr - max)) + elseif p[3] - p[2] == -1 then + d = math.min(d, math.max(0, max - ctr - MINDIF)) + end + + if p[3] == 1 then + d = math.min(d, math.max(0, MAXOUT - max)) + end + + -- Update output values + output.min = min + p[1] * d + output.offset = ctr + p[2] * d + output.max = max + p[3] * d + + -- Write back data + model.setOutput(channel.iChannel - 1, output) + end + + function interval.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER and not channel.editing then + channel.editing = true + editPrompt.onEvent(EVT_VIRTUAL_ENTER) + channel.showPrompt(editPrompt) + return + end + + if event == EVT_TOUCH_SLIDE and iScroll > 0 then + local p = activePoints(editPoints)[iScroll] + local d = STEP * math.floor(p * (touchState.x - x[iScroll]) * SCALE / STEP + 0.5) + adjustPoints(d) + else + iScroll = 0 + end + + if event == EVT_TOUCH_FIRST then + iScroll = ptCovers(touchState.x, touchState.y) + if iScroll > 0 then + x0 = x[iScroll] + end + elseif libGUI.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + editPoints = 0 + channel.editing = false + elseif event == EVT_VIRTUAL_INC then + adjustPoints(STEP) + elseif event == EVT_VIRTUAL_DEC then + adjustPoints(-STEP) + end + end -- onEvent(...) + end -- Setup interval + end + end + end +end -- init() + +function widget.refresh(event, touchState) + if not event then + gui = nil + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + init() + return + end + + gui.run(event, touchState) +end -- refresh(...) + +function widget.background() + gui = nil +end -- background() diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua new file mode 100644 index 00000000..33e32190 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/switch.lua @@ -0,0 +1,214 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K switch setup, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-14 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui +local colors = libGUI.colors +local title = "Switches" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 25 +local LINE = 29 +local HEIGHT = 25 +local WIDTH = 60 +local COL2 = LCD_W - MARGIN - WIDTH + +-- List of 1. Text label 2. logical switch +local items_F3K = { -- For R3K + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, + { "Data logging (when flight timer is running)", 7 } +} + +local items_F3K_RE = { -- For R3K_RE + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, + { "Data logging (when flight timer is running)", 7 } +} + +local items_F5K = { + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Motor ARM ON/OFF", 4}, + { "Report remaining window time every 10 sec.", 5 }, + { "Report current altitude every 10 sec.", 6 }, + { "Launch mode and flight timer control", 7 }, + { "Data logging (when flight timer is running)", 8 } +} + +local items_FxJ = { + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 6 }, + { "Report current altitude every 10 sec.", 7 }, + { "Launch mode (Motor Arm) and flight timer control", 4 }, + { "Start/Stop timer and Motor", 8 }, + { "Data logging (when flight timer is running)", 9 } +} + +local items_FXY = { + { "Allow vario and voice reporting of altitude", 0 } +} + +local items = items_FXY + +-------------------------------- Setup GUI -------------------------------- + +local function init() + gui = libGUI.newGUI() + + function gui.fullScreenRefresh() + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Row background + for i = 0, 7 do + local y = HEADER + i * LINE + if i % 2 == 1 then + lcd.drawFilledRectangle(0, y, LCD_W, LINE, COLOR_THEME_SECONDARY2) + else + lcd.drawFilledRectangle(0, y, LCD_W, LINE, COLOR_THEME_SECONDARY3) + end + end + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Build the list of drop downs + local y = HEADER + 2 + local w1 = COL2 - MARGIN + + -- Build lists of physical switch position indices and names + local swIndices = { } + local swNames = { } + local MAX_SW = getSwitchIndex(CHAR_TRIM .. "Rl") - 1 + for swIdx, swName in switches(-MAX_SW, MAX_SW) do + if swIdx ~= 0 then + i = #swIndices + 1 + swIndices[i] = swIdx + swNames[i] = swName + end + end + + local function setSwitch(dropDown) + lsTbl = model.getLogicalSwitch(dropDown.ls) + swIdx = swIndices[dropDown.selected] + lsTbl.v1 = swIdx + model.setLogicalSwitch(dropDown.ls, lsTbl) + end + + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_FH" or modelType == "F3K_TRAD" then + items = items_F3K + elseif modelType == "F3K_RE" then + items = items_F3K_RE + elseif modelType == "F5K" then + items = items_F5K -- Make it smaller to fit extra line + HEIGHT = 20 + LINE = 25 + elseif modelType == "F3J" or modelType == "F5J" then + items = items_FxJ + HEIGHT = 20 -- Make it smaller to fit extra line + LINE = 25 + else + items = items_FXY + modelType = "F??" + end + + for i, item in ipairs(items) do + gui.label(MARGIN, y, w1, HEIGHT, item[1]) + + local swIdx = model.getLogicalSwitch(item[2]).v1 + local selected = 0 + + for i, idx in ipairs(swIndices) do + if swIdx == idx then + selected = i + break + end + end + + if selected == 0 then + -- Oops, no switch matching current value in LS! + gui.label(COL2, y, WIDTH, HEIGHT, "???", CENTER + BOLD) + else + local dropDown = gui.dropDown(COL2, y, WIDTH, HEIGHT, swNames, selected, setSwitch, CENTER) + dropDown.ls = item[2] + end + + y = y + LINE + end +end -- init() + +function widget.background() + gui = nil +end -- background() + +function widget.refresh(event, touchState) + if not event then + gui = nil + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + init() + return + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua new file mode 100644 index 00000000..78a72828 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/wing2.lua @@ -0,0 +1,359 @@ +--------------------------------------------------------------------------- +-- SoarETX flaperon alignment, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-06-26 -- +-- Version: 1.0.1 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui = nil +local colors = libGUI.colors +local title = "Wing alignment" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 40 +local HEIGHT = 150 +local WIDTH = (LCD_W - 3 * DIST_X) / 2 +local TEXT_Y = 210 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 + +-- Other constants +local INP_STEP = getFieldInfo("input7").id -- Step input +local LS_STEP = nil -- Set this LS to apply step input and adjust (model type specific) +local N = 5 -- Number of curve points +local MAX_Y = 1500 -- Max output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels + +-- Flaperon curve indices +local CRV_LFT = 0 +local CRV_RGT = 1 +-- Tables with data for flaperon curves +local lftCrv +local rgtCrv +-- Indices of output channels +local lftOutIdx +local rgtOutIdx +-- Tables with data for flaperon output channels +local lftOut +local rgtOut +-- Tables with y-values after both curve and output settings have been applied +local lftYs = { } +local rgtYs = { } +local activeP -- The point currently being edited + + + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, false) end +end + +local function stepOn() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, true) end +end + + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + gui = nil + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +-- Find the output where the specified curve index is being used +local function GetOutput(crvIndex) + for i = 0, NC - 1 do + local out = model.getOutput(i) + + if out and out.curve == crvIndex then + return i, out + end + end + + stepOff() + gui = nil + error("No output channel with curve CV" .. crvIndex + 1) +end -- GetOutput() + +local function init() + lftCrv = GetCurve(CRV_LFT) + lftOutIdx, lftOut = GetOutput(CRV_LFT) + rgtCrv = GetCurve(CRV_RGT) + rgtOutIdx, rgtOut = GetOutput(CRV_RGT) + stepOn() +end -- init() + +-- Find index of the curve point that corresponds to the value of the step input +local function FindPoint() + local x = getValue(INP_STEP) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) +end -- FindPoint() + +-- Compute output after applying curve and center/endpoints +local function ComputeYs(crv, out, y) + for p = 1, N do + if crv.y[p] < 0 then + y[p] = out.offset + 0.01 * crv.y[p] * (out.offset - out.min) + else + y[p] = out.offset + 0.01 * crv.y[p] * (out.max - out.offset) + end + end +end -- ComputeYs() + +-- Reverse curve points on the left side +local function reverse(ys) + for i = 1, math.floor((N + 1) / 2) do + ys[i], ys[N + 1 - i] = -ys[N + 1 - i], -ys[i] + end +end + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjustment is +/-750 around this offset +local function offset() + local ctr = (N + 1) / 2 + return (activeP - ctr) * 750 / (ctr - 1) +end + +-- Adjust a point, either on a curve or output +local function adjustPoint(crvIdx, crvTbl, outIdx, outTbl, activeP, y) + if activeP == 1 then + outTbl.min = math.min(y, outTbl.offset - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == (N + 1) / 2 then + outTbl.offset = math.min(math.max(y, outTbl.min + MINDIF), outTbl.max - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == N then + outTbl.max = math.max(y, outTbl.offset + MINDIF) + model.setOutput(outIdx, outTbl) + else + crvTbl.y[activeP] = 0.1 * y + model.setCurve(crvIdx, crvTbl) + end +end + +-- Adjust the reversed left curve +local function adjLft(slider) + adjustPoint(CRV_LFT, lftCrv, lftOutIdx, lftOut, N + 1 - activeP, -slider.value - offset()) +end + +-- Adjust the right curve +local function adjRgt(slider) + adjustPoint(CRV_RGT, rgtCrv, rgtOutIdx, rgtOut, activeP, slider.value + offset()) +end + +-- The inverse function of adjust to set slider value from current settings +local function sliderPoint(crvTbl, outTbl, reverse) + local value + local activeP = activeP + + if reverse then + activeP = N + 1 - activeP + end + + if activeP == 1 then + value = outTbl.min + elseif activeP == (N + 1) / 2 then + value = outTbl.offset + elseif activeP == N then + value = outTbl.max + else + value = 10 * crvTbl.y[activeP] + end + + if reverse then + value = -value + end + + return 10 * math.floor(0.1 * (value - offset()) + 0.5) +end + +-- Reset outputs +local function reset() + local midpt = (N + 1) / 2 + + for p = 1, N do + local y = 200.0 / (N - 1) * (p - midpt) + lftCrv.y[p] = y + rgtCrv.y[p] = y + end + model.setCurve(CRV_RGT, rgtCrv) + model.setCurve(CRV_LFT, lftCrv) + + lftOut.min = -1000 + lftOut.offset = 0 + lftOut.max = 1000 + model.setOutput(lftOutIdx, lftOut) + + rgtOut.min = -1000 + rgtOut.offset = 0 + rgtOut.max = 1000 + model.setOutput(rgtOutIdx, rgtOut) + + init() +end -- Reset() + +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + gui = libGUI.newGUI() + + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_TRAD" then + LS_STEP = 10 -- Logical Switch 10 + else + LS_STEP = 10 + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + drawCurve(DIST_X, TOP, WIDTH, HEIGHT, lftYs) + drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, rgtYs) + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen.\n" .. + "First end points, then center, and finally +/-50%." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + local lftSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjLft) + + function lftSlider.update() + lftSlider.value = sliderPoint(lftCrv, lftOut, true) + end + + local rgtSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjRgt) + + function rgtSlider.update() + rgtSlider.value = sliderPoint(rgtCrv, rgtOut, false) + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if gui ~= nil then + gui = nil + stepOff() + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = FindPoint() + ComputeYs(lftCrv, lftOut, lftYs) + reverse(lftYs) + ComputeYs(rgtCrv, rgtOut, rgtYs) + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua b/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua new file mode 100644 index 00000000..b7b112a4 --- /dev/null +++ b/sdcard/c480x272/WIDGETS/SoarETX/2/wing4.lua @@ -0,0 +1,382 @@ +--------------------------------------------------------------------------- +-- SoarETX flaps and aileron alignment, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-20 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui = nil +local colors = libGUI.colors +local title = "Wing alignment" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 25 +local HEIGHT = 150 +local WIDTH = (LCD_W - 4.5 * DIST_X) / 4 +local TEXT_Y = 210 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 + +-- Other constants +local INP_STEP = getFieldInfo("input8").id -- Step input +local LS_STEP = nil -- Set this LS to apply step input and adjust +local GV_ADJUST = nil +local N = 5 -- Number of curve points +local MAX_Y = 1500 -- Max output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels + +-- Flaperon curve indices (LA, LF, RF, RA) +local CRV_IDX = { 0, 2, 3, 1 } +-- Tables with data for flaperon curves +local crvTbls = { {}, {}, {}, {} } +-- Indices of output channels +local outIds = { {}, {}, {}, {} } +-- Tables with data for flaperon output channels +local outTbls = { {}, {}, {}, {} } +-- Tables with y-values after both curve and output settings have been applied +local yVals = { {}, {}, {}, {} } +-- The point currently being edited +local activeP +-- Labels for curve plots +local labels = { + "Lft ail", + "Lft flp", + "Rgt flp", + "Rgt ail" +} + +-- Step Adjusting input has be turned on by this widget +local function isAdjustin() + local r = false + if (LS_STEP ~= nil) then r = getStickySwitch(LS_STEP) + elseif (GV_ADJUST ~= nil) then r = model.getGlobalVariable(GV_ADJUST, 0)==1 end + return r +end + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, false) end + if (GV_ADJUST ~= nil) then model.setGlobalVariable(GV_ADJUST, 0, 0) end +end + +local function stepOn() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, true) end + if (GV_ADJUST ~= nil) then model.setGlobalVariable(GV_ADJUST, 0, 1) end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +-- Find the output where the specified curve index is being used +local function GetOutput(crvIndex) + for i = 0, NC - 1 do + local out = model.getOutput(i) + + if out and out.curve == crvIndex then + return i, out + end + end + + stepOff() + error("No output channel with curve CV" .. crvIndex + 1) +end -- GetOutput() + +local function init() + for i, j in ipairs(CRV_IDX) do + crvTbls[i] = GetCurve(j) + outIds[i], outTbls[i] = GetOutput(j) + end + + stepOn() +end -- init() + +-- Find index of the curve point that corresponds to the value of the step input +local function FindPoint() + local x = getValue(INP_STEP) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) +end -- FindPoint() + +-- Compute output after applying curve and center/endpoints +local function ComputeYs() + for i, j in ipairs(CRV_IDX) do + local crv = crvTbls[i] + local out = outTbls[i] + local y = yVals[i] + + for p = 1, N do + if crv.y[p] < 0 then + y[p] = out.offset + 0.01 * crv.y[p] * (out.offset - out.min) + else + y[p] = out.offset + 0.01 * crv.y[p] * (out.max - out.offset) + end + end + + if i <= 2 then + -- Reverse curve points on the left side + for k = 1, math.floor((N + 1) / 2) do + y[k], y[N + 1 - k] = -y[N + 1 - k], -y[k] + end + end + end +end -- ComputeYs() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjustment is +/-750 around this offset +local function offset() + local ctr = (N + 1) / 2 + return (activeP - ctr) * 750 / (ctr - 1) +end + +-- Adjust a point, either on a curve or output +local function adjustPoint(i, slider) + local crvIdx = CRV_IDX[i] + local crvTbl = crvTbls[i] + local outIdx = outIds[i] + local outTbl = outTbls[i] + local activeP = activeP + local y = slider.value + offset() + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + y = -y + end + + if activeP == 1 then + outTbl.min = math.min(y, outTbl.offset - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == (N + 1) / 2 then + outTbl.offset = math.min(math.max(y, outTbl.min + MINDIF), outTbl.max - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == N then + outTbl.max = math.max(y, outTbl.offset + MINDIF) + model.setOutput(outIdx, outTbl) + else + crvTbl.y[activeP] = 0.1 * y + model.setCurve(crvIdx, crvTbl) + end +end + +-- The inverse function of adjust to set slider value from current settings +local function sliderPoint(i) + local crvTbl = crvTbls[i] + local outTbl = outTbls[i] + local activeP = activeP + local value + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + end + + if activeP == 1 then + value = outTbl.min + elseif activeP == (N + 1) / 2 then + value = outTbl.offset + elseif activeP == N then + value = outTbl.max + else + value = 10 * crvTbl.y[activeP] + end + + if i <= 2 then + value = -value + end + + return 10 * math.floor(0.1 * (value - offset()) + 0.5) +end + +-- Reset outputs +local function reset() + local midpt = (N + 1) / 2 + + for i, j in ipairs(CRV_IDX) do + local crvTbl = crvTbls[i] + for p = 1, N do + local y = 200.0 / (N - 1) * (p - midpt) + crvTbl.y[p] = y + end + model.setCurve(j, crvTbl) + + local outTbl = outTbls[i] + outTbl.min = -1000 + outTbl.offset = 0 + outTbl.max = 1000 + model.setOutput(outIds[i], outTbl) + end + + init() +end -- Reset() + +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + gui = libGUI.newGUI() + + -- Extract Model Type from parametes + modelType = widget.options.Type + if modelType == "F3K_FH" then + LS_STEP = 10 -- L11 + elseif modelType == "F3J" or modelType == "F5J" then + GV_ADJUST = 7 -- GV8:Adj + else + LS_STEP = nil + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + for i, j in ipairs(CRV_IDX) do + local x = (i - 1) * (DIST_X + WIDTH) + DIST_X + if i > 2 then + x = x - DIST_X / 2 + end + drawCurve(x, TOP, WIDTH, HEIGHT, yVals[i]) + lcd.drawText(x + 2, TOP, labels[i], SMLSIZE + colors.primary1) + end + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen.\n" .. + "First end points, then center, and finally +/-50%." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + for i, j in ipairs(CRV_IDX) do + local x = DIST_X / 2 + (i - 1) * (DIST_X + WIDTH) + if i > 2 then + x = x + WIDTH + DIST_X / 2 + end + local slider = gui.verticalSlider(x, TOP, HEIGHT, 0, -750, 750, 10, function(slider) adjustPoint(i, slider) end) + + function slider.update() + slider.value = sliderPoint(i) + end + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + gui=nil + stepOff() +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = FindPoint() + ComputeYs() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x272/WIDGETS/SoarETX/main.lua b/sdcard/c480x272/WIDGETS/SoarETX/main.lua index af920d7e..fe3c5332 100644 --- a/sdcard/c480x272/WIDGETS/SoarETX/main.lua +++ b/sdcard/c480x272/WIDGETS/SoarETX/main.lua @@ -2,8 +2,9 @@ -- SoarETX widget -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-11-22 -- --- Version: 1.0.1 -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -21,7 +22,8 @@ local options = { { "Version", VALUE, 1, 1, 99 }, - { "FileName", STRING, "" } + { "FileName", STRING, "" }, + { "Type", STRING, "" } } local soarGlobals @@ -75,16 +77,42 @@ local function Load(widget) end end +local function GetCurve(crvIndex) + local N = 5 + + local oldTbl = model.getCurve(crvIndex) + + if #oldTbl.y == N then -- Normal Behaviour + return oldTbl + end + + -- Work arround the bug of GetCurve in some versions (2.8.3) of ETX + if #oldTbl.y == N - 1 then + local newTbl = { } + newTbl.y = { } + for p = 1, N do + newTbl.y[p] = oldTbl.y[p - 1] + end + newTbl.smooth = 1 + newTbl.name = oldTbl.name + return newTbl + end + + return oldTbl +end -- GetCurve() + + -- Initialize the first time this widget is instantiated local function init() soarGlobals = { path = "/WIDGETS/SoarETX/", battery = 0, - batteryParameter = 1 + batteryParameter = 1, + getCurve = GetCurve } -- Functions to handle persistent model parameters stored in curve 32 - local parameterCurve = model.getCurve(31) + local parameterCurve = GetCurve(31) if not parameterCurve then error("Curve #32 is missing! It is used to store persistent model parameters for Lua.") diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.txt b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.txt new file mode 100644 index 00000000..6d75419e --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.txt @@ -0,0 +1 @@ +DLG model with rudder and elevator only. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.yml b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.yml new file mode 100644 index 00000000..611493b8 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K RE.yml @@ -0,0 +1,559 @@ +header: + name: F3K RE + bitmap: "" +timers: + 0: + swtch: L16 + mode: ON + name: Flight + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 + 1: + swtch: L15 + mode: ON + name: Window + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +disableThrottleWarning: 1 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +flightModeData: + 0: + name: Cruise + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 40 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + swtch: L7 + name: Launch + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 20 + mode: 1 + 1: + value: 20 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + swtch: L13 + name: Zoom + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 20 + mode: 1 + 2: + value: 0 + mode: 31 + swtch: L3 + name: Speed + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 8: + val: 50 +mixData: + - destCh: 0 + srcRaw: I0 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" +limitData: + 0: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Rudd + curve: 0 + 1: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Elev + curve: 0 + 4: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 5: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 6: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: Ail + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 0 + name: Rudder + - srcRaw: Ele + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: GV7 + offset: 0 + curve: + type: 1 + value: GV9 + carryTrim: 0 + name: Elevat + - srcRaw: S1 + scale: 0 + mode: 3 + chn: 2 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Dial +inputNames: + 0: + val: Rudd + 1: + val: Elev + 2: + val: Pokr +curves: + 31: + type: 0 + smooth: 0 + points: 0 + name: Mem +points: + 155: + val: 0 + 156: + val: 0 + 157: + val: 0 + 158: + val: 0 + 159: + val: 0 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + delay: 0 + duration: 0 + andsw: L16 + 1: + func: FUNC_AND + def: SA2,NONE + delay: 0 + duration: 0 + andsw: NONE + 2: + func: FUNC_AND + def: SB0,NONE + delay: 0 + duration: 0 + andsw: NONE + 3: + func: FUNC_AND + def: L7,NONE + delay: 0 + duration: 3 + andsw: NONE + 4: + func: FUNC_AND + def: SD0,NONE + delay: 0 + duration: 0 + andsw: NONE + 5: + func: FUNC_AND + def: SD2,NONE + delay: 0 + duration: 0 + andsw: L1 + 6: + func: FUNC_OR + def: SF2,L4 + delay: 0 + duration: 0 + andsw: NONE + 7: + func: FUNC_AND + def: SH2,NONE + delay: 0 + duration: 0 + andsw: NONE + 9: + func: FUNC_ADIFFEGREATER + def: Ail,6 + delay: 0 + duration: 0 + andsw: NONE + 10: + func: FUNC_ADIFFEGREATER + def: Ele,6 + delay: 0 + duration: 0 + andsw: NONE + 11: + func: FUNC_OR + def: L10,L11 + delay: 0 + duration: 0 + andsw: NONE + 12: + func: FUNC_STICKY + def: FM1,L12 + delay: 0 + duration: 0 + andsw: NONE + 14: + func: FUNC_STICKY + def: L15,NONE + delay: 0 + duration: 0 + andsw: NONE + 15: + func: FUNC_STICKY + def: L16,NONE + delay: 0 + duration: 0 + andsw: NONE + 17: + func: FUNC_OR + def: FM1,FM2 + delay: 0 + duration: 0 + andsw: NONE + 18: + func: FUNC_AND + def: L18,L16 + delay: 0 + duration: 0 + andsw: L8 + 19: + func: FUNC_AND + def: "!L19,L16" + delay: 0 + duration: 0 + andsw: L8 +customFn: + 0: + swtch: L2 + func: VARIO + 1: + swtch: L5 + func: PLAY_VALUE + def: TIMER2,10 + 2: + swtch: L19 + func: LOGS + def: 10 + 3: + swtch: L20 + func: LOGS + def: 100 +swashR: + type: TYPE_NONE + value: 0 + collectiveSource: NONE + aileronSource: NONE + elevatorSource: NONE + collectiveWeight: 0 + aileronWeight: 0 + elevatorWeight: 0 +thrTraceSrc: Thr +switchWarningState: "" +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +potsWarnEnabled: 0 +displayChecklist: 0 +gvars: + 6: + name: Ele + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: Exp + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rssiAlarms: + disabled: 0 + warning: 0 + critical: 0 +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +screenData: + 0: + LayoutId: Layout1x1 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: Layout2x3 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: outputs + 1: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3kre_mx + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: graph + 5: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3kre_sw + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: name + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: battery +view: 0 diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.txt b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.txt new file mode 100644 index 00000000..ca437ecf --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.txt @@ -0,0 +1 @@ +DLG model with "traditional" mixes, but the same features as the advanced F3K model. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/F3K TRAD.yml b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.yml similarity index 100% rename from sdcard/c480x320/TEMPLATES/SoarETX/F3K TRAD.yml rename to sdcard/c480x320/TEMPLATES/3.SoarETX/F3K TRAD.yml diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K-TRAD.yml b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K-TRAD.yml new file mode 100644 index 00000000..0cbeda58 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K-TRAD.yml @@ -0,0 +1,1192 @@ +header: + name: F3K-TRAD + bitmap: "" +timers: + 0: + swtch: L16 + mode: ON + name: Flight + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 + 1: + swtch: L15 + mode: ON + name: Window + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +disableThrottleWarning: 1 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: Cruise + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 66 + 1: + val: 67 + 2: + val: 10 + 4: + val: 12 + 5: + val: 25 + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 0 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + swtch: L7 + name: Launch + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + swtch: L21 + name: Zoom + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + swtch: L3 + name: Speed + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 8 + swtch: L4 + name: Float + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 +mixData: + - destCh: 0 + srcRaw: I0 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 0 + srcRaw: I2 + weight: GV3 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 1 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: AilRud + - destCh: 1 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: ch(29) + weight: -GV5 + swtch: NONE + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: GV5 + name: BrkEle + - destCh: 2 + srcRaw: I2 + weight: GV1 + swtch: "!L13" + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 2 + srcRaw: ch(31) + weight: -100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 3 + srcRaw: I2 + weight: GV1 + swtch: "!L13" + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 3 + srcRaw: ch(31) + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 29 + srcRaw: I3 + weight: 100 + swtch: NONE + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 29 + srcRaw: MAX + weight: 100 + swtch: L25 + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: REPL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: BrkOff + - destCh: 30 + srcRaw: I5 + weight: 10 + swtch: NONE + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 011001111 + offset: -10 + name: Slider + - destCh: 30 + srcRaw: I4 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 30 + srcRaw: I1 + weight: GV6 + swtch: NONE + curve: + type: 3 + value: 4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: SnpFlp + - destCh: 31 + srcRaw: ch(29) + weight: GV2 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Brake + - destCh: 31 + srcRaw: MAX + weight: GV2 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: -100 + name: Offset + - destCh: 31 + srcRaw: ch(30) + weight: 100 + swtch: "!L13" + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Camber + - destCh: 31 + srcRaw: I6 + weight: 100 + swtch: L11 + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: REPL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Align +limitData: + 0: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Rudd + curve: 0 + 1: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Elev + curve: 0 + 2: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Left + curve: 1 + 3: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Right + curve: 2 + 4: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 5: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 6: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: Rud + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 0 + name: Rudder + - srcRaw: Ele + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: GV7 + offset: 0 + curve: + type: 1 + value: GV9 + carryTrim: 0 + name: Elevat + - srcRaw: Ail + scale: 0 + mode: 3 + chn: 2 + swtch: NONE + flightModes: 000000000 + weight: GV8 + offset: 0 + curve: + type: 1 + value: GV9 + carryTrim: 0 + name: Ailero + - srcRaw: Thr + scale: 0 + mode: 3 + chn: 3 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Brake + - srcRaw: TrimThr + scale: 0 + mode: 3 + chn: 4 + swtch: NONE + flightModes: 000000000 + weight: 50 + offset: 0 + curve: + type: 0 + value: -100 + carryTrim: 1 + name: CambPs + - srcRaw: MAX + scale: 0 + mode: 3 + chn: 5 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Camber + - srcRaw: Thr + scale: 0 + mode: 3 + chn: 6 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 3 + value: 7 + carryTrim: 1 + name: Align + - srcRaw: S1 + scale: 0 + mode: 3 + chn: 7 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Dial +inputNames: + 0: + val: Rudd + 1: + val: Elev + 2: + val: Aile + 3: + val: Brk + 4: + val: CbPS + 5: + val: Cmb + 6: + val: Aln + 7: + val: Pokr +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: Lft + 1: + type: 0 + smooth: 1 + points: 0 + name: Rgt + 2: + type: 0 + smooth: 0 + points: -2 + name: BrF + 3: + type: 1 + smooth: 0 + points: -1 + name: Snp + 4: + type: 0 + smooth: 0 + points: -2 + name: Abs + 5: + type: 1 + smooth: 0 + points: -2 + name: DB + 6: + type: 1 + smooth: 0 + points: 5 + name: Aln + 31: + type: 0 + smooth: 0 + points: 0 + name: Mem +points: + 0: + val: -100 + 1: + val: -50 + 2: + val: 0 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 7: + val: 0 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: 50 + 12: + val: 100 + 13: + val: -100 + 14: + val: -100 + 15: + val: 0 + 16: + val: 0 + 17: + val: -50 + 18: + val: 0 + 19: + val: 100 + 20: + val: 0 + 21: + val: 100 + 22: + val: -100 + 23: + val: 100 + 24: + val: 100 + 25: + val: 90 + 26: + val: -100 + 27: + val: -100 + 28: + val: -50 + 29: + val: -50 + 30: + val: 0 + 31: + val: 0 + 32: + val: 50 + 33: + val: 50 + 34: + val: 100 + 35: + val: 100 + 36: + val: -75 + 37: + val: -75 + 38: + val: -25 + 39: + val: -25 + 40: + val: 25 + 41: + val: 25 + 42: + val: 75 + 43: + val: 75 + 164: + val: 0 + 165: + val: 0 + 166: + val: 0 + 167: + val: 0 + 168: + val: 0 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + delay: 0 + duration: 0 + andsw: L16 + 1: + func: FUNC_AND + def: SA2,NONE + delay: 0 + duration: 0 + andsw: NONE + 2: + func: FUNC_AND + def: SB0,NONE + delay: 0 + duration: 0 + andsw: NONE + 3: + func: FUNC_AND + def: SB2,NONE + delay: 0 + duration: 0 + andsw: NONE + 4: + func: FUNC_AND + def: SD0,NONE + delay: 0 + duration: 0 + andsw: NONE + 5: + func: FUNC_AND + def: SD2,NONE + delay: 0 + duration: 0 + andsw: L1 + 6: + func: FUNC_OR + def: SF2,L9 + delay: 0 + duration: 0 + andsw: NONE + 7: + func: FUNC_AND + def: SH2,NONE + delay: 0 + duration: 0 + andsw: NONE + 8: + func: FUNC_AND + def: L7,NONE + delay: 0 + duration: 3 + andsw: NONE + 10: + func: FUNC_STICKY + def: L11,NONE + delay: 0 + duration: 0 + andsw: NONE + 11: + func: FUNC_STICKY + def: L12,NONE + delay: 0 + duration: 0 + andsw: NONE + 12: + func: FUNC_OR + def: L11,L12 + delay: 0 + duration: 0 + andsw: NONE + 14: + func: FUNC_STICKY + def: L15,NONE + delay: 0 + duration: 0 + andsw: NONE + 15: + func: FUNC_STICKY + def: L16,NONE + delay: 0 + duration: 0 + andsw: NONE + 17: + func: FUNC_ADIFFEGREATER + def: Ail,6 + delay: 0 + duration: 0 + andsw: NONE + 18: + func: FUNC_ADIFFEGREATER + def: Ele,6 + delay: 0 + duration: 0 + andsw: NONE + 19: + func: FUNC_OR + def: L18,L19 + delay: 0 + duration: 0 + andsw: NONE + 20: + func: FUNC_STICKY + def: FM1,L20 + delay: 0 + duration: 0 + andsw: NONE + 22: + func: FUNC_VPOS + def: I3,90 + delay: 0 + duration: 0 + andsw: "!FM1" + 23: + func: FUNC_STICKY + def: FM1,L23 + delay: 0 + duration: 0 + andsw: NONE + 24: + func: FUNC_OR + def: L24,L13 + delay: 0 + duration: 0 + andsw: NONE + 25: + func: FUNC_AND + def: "!FM1,L24" + delay: 30 + duration: 0 + andsw: "!L23" + 27: + func: FUNC_OR + def: FM1,FM2 + delay: 0 + duration: 0 + andsw: NONE + 28: + func: FUNC_AND + def: L28,L16 + delay: 0 + duration: 0 + andsw: L8 + 29: + func: FUNC_AND + def: "!L29,L16" + delay: 0 + duration: 0 + andsw: L8 +customFn: + 0: + swtch: L2 + func: VARIO + 1: + swtch: L5 + func: PLAY_VALUE + def: TIMER2,10 + 2: + swtch: L26 + func: PLAY_TRACK + def: flapup,5 + 3: + swtch: L29 + func: LOGS + def: 10 + 4: + swtch: L30 + func: LOGS + def: 100 +swashR: + type: TYPE_NONE + value: 0 + collectiveSource: NONE + aileronSource: NONE + elevatorSource: NONE + collectiveWeight: 0 + aileronWeight: 0 + elevatorWeight: 0 +thrTraceSrc: Thr +switchWarningState: "" +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +potsWarnEnabled: 0 +displayChecklist: 0 +gvars: + 0: + name: Ail + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: Brk + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 2: + name: AiR + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 3: + name: Dif + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 4: + name: BkE + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 5: + name: Snp + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 6: + name: Ele + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 7: + name: Ail + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: Exp + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rssiAlarms: + disabled: 0 + warning: 0 + critical: 0 +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +screenData: + 0: + LayoutId: Layout1x1 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: Layout2x3 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: outputs + 1: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: wing2 + 2: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_mix + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_ctr + 4: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: graph + 5: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_sw + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: name + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: battery +view: 0 diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.txt b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.txt new file mode 100644 index 00000000..bbf15a78 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.txt @@ -0,0 +1,2 @@ +DLG model with advanced mixes. +Always full aileron control, as flaps are automatically retracted, if needed. Snap-flaps are compensated for camber preset, to avoid excessive movement. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.yml b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.yml new file mode 100644 index 00000000..28fdbe32 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/3.SoarETX/F3K.yml @@ -0,0 +1,1362 @@ +header: + name: F3K + bitmap: "" +timers: + 0: + swtch: L16 + mode: ON + name: Flight + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 + 1: + swtch: L15 + mode: ON + name: Window + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: -1 + value: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +disableThrottleWarning: 1 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: Cruise + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 66 + 1: + val: 67 + 2: + val: 10 + 4: + val: 12 + 5: + val: 25 + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 0 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + swtch: L7 + name: Launch + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + swtch: L21 + name: Zoom + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + swtch: L3 + name: Speed + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 8 + swtch: L4 + name: Float + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 +mixData: + - destCh: 0 + srcRaw: I0 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 0 + srcRaw: I2 + weight: GV3 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 1 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: AilRud + - destCh: 1 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: ch(24) + weight: -GV5 + swtch: NONE + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: GV5 + name: BrkEle + - destCh: 2 + srcRaw: I2 + weight: GV1 + swtch: "!L13" + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 2 + srcRaw: ch(31) + weight: -100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 3 + srcRaw: I2 + weight: GV1 + swtch: "!L13" + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 3 + srcRaw: ch(31) + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 24 + srcRaw: I3 + weight: 100 + swtch: NONE + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Brake + - destCh: 24 + srcRaw: MAX + weight: 100 + swtch: L25 + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: REPL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: BrkOff + - destCh: 25 + srcRaw: I4 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: SnpNeg + - destCh: 25 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 3 + value: -4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 1 + mltpx: MUL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 26 + srcRaw: I4 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: GV6 + name: SnpPos + - destCh: 26 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 3 + value: 4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 1 + mltpx: MUL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 27 + srcRaw: I5 + weight: 10 + swtch: NONE + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 011001111 + offset: -10 + name: Slider + - destCh: 27 + srcRaw: I4 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 27 + srcRaw: ch(25) + weight: 100 + swtch: NONE + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 27 + srcRaw: ch(26) + weight: 100 + swtch: NONE + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 28 + srcRaw: ch(24) + weight: GV2 + swtch: NONE + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Flap + - destCh: 28 + srcRaw: MAX + weight: GV2 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: -100 + name: Offset + - destCh: 28 + srcRaw: ch(27) + weight: 100 + swtch: "!L13" + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 29 + srcRaw: I2 + weight: GV1 + swtch: NONE + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 1 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: AbsAil + - destCh: 30 + srcRaw: ch(28) + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 100 + name: DwnExc + - destCh: 30 + srcRaw: ch(29) + weight: -100 + swtch: NONE + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: AilDow + - destCh: 31 + srcRaw: ch(28) + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Flap + - destCh: 31 + srcRaw: ch(30) + weight: -100 + swtch: NONE + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: BmpUp + - destCh: 31 + srcRaw: I6 + weight: 100 + swtch: L11 + curve: + type: 0 + value: 0 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: REPL + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Align +limitData: + 0: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Rudd + curve: 0 + 1: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Elev + curve: 0 + 2: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Left + curve: 1 + 3: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: Right + curve: 2 + 4: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 5: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 + 6: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: Rud + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 0 + name: Rudder + - srcRaw: Ele + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: GV7 + offset: 0 + curve: + type: 1 + value: GV9 + carryTrim: 0 + name: Elevat + - srcRaw: Ail + scale: 0 + mode: 3 + chn: 2 + swtch: NONE + flightModes: 000000000 + weight: GV8 + offset: 0 + curve: + type: 1 + value: GV9 + carryTrim: 0 + name: Ailero + - srcRaw: Thr + scale: 0 + mode: 3 + chn: 3 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Brake + - srcRaw: TrimThr + scale: 0 + mode: 3 + chn: 4 + swtch: NONE + flightModes: 000000000 + weight: 50 + offset: 0 + curve: + type: 0 + value: -100 + carryTrim: 1 + name: CambPs + - srcRaw: MAX + scale: 0 + mode: 3 + chn: 5 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Camber + - srcRaw: Thr + scale: 0 + mode: 3 + chn: 6 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 3 + value: 7 + carryTrim: 1 + name: Align + - srcRaw: S1 + scale: 0 + mode: 3 + chn: 7 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + carryTrim: 1 + name: Dial +inputNames: + 0: + val: Rudd + 1: + val: Elev + 2: + val: Aile + 3: + val: Brk + 4: + val: CbPS + 5: + val: Cmb + 6: + val: Aln + 7: + val: Pokr +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: Lft + 1: + type: 0 + smooth: 1 + points: 0 + name: Rgt + 2: + type: 0 + smooth: 0 + points: -2 + name: BrF + 3: + type: 1 + smooth: 0 + points: -1 + name: Snp + 4: + type: 0 + smooth: 0 + points: -2 + name: Abs + 5: + type: 1 + smooth: 0 + points: -2 + name: DB + 6: + type: 1 + smooth: 0 + points: 5 + name: Aln + 31: + type: 0 + smooth: 0 + points: 0 + name: Mem +points: + 0: + val: -100 + 1: + val: -50 + 2: + val: 0 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 7: + val: 0 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: 50 + 12: + val: 100 + 13: + val: -100 + 14: + val: -100 + 15: + val: 0 + 16: + val: 0 + 17: + val: -50 + 18: + val: 0 + 19: + val: 100 + 20: + val: 0 + 21: + val: 100 + 22: + val: -100 + 23: + val: 100 + 24: + val: 100 + 25: + val: 90 + 26: + val: -100 + 27: + val: -100 + 28: + val: -50 + 29: + val: -50 + 30: + val: 0 + 31: + val: 0 + 32: + val: 50 + 33: + val: 50 + 34: + val: 100 + 35: + val: 100 + 36: + val: -75 + 37: + val: -75 + 38: + val: -25 + 39: + val: -25 + 40: + val: 25 + 41: + val: 25 + 42: + val: 75 + 43: + val: 75 + 164: + val: 0 + 165: + val: 0 + 166: + val: 0 + 167: + val: 0 + 168: + val: 0 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + delay: 0 + duration: 0 + andsw: L16 + 1: + func: FUNC_AND + def: SA2,NONE + delay: 0 + duration: 0 + andsw: NONE + 2: + func: FUNC_AND + def: SB0,NONE + delay: 0 + duration: 0 + andsw: NONE + 3: + func: FUNC_AND + def: SB2,NONE + delay: 0 + duration: 0 + andsw: NONE + 4: + func: FUNC_AND + def: SD0,NONE + delay: 0 + duration: 0 + andsw: NONE + 5: + func: FUNC_AND + def: SD2,NONE + delay: 0 + duration: 0 + andsw: L1 + 6: + func: FUNC_OR + def: SF2,L9 + delay: 0 + duration: 0 + andsw: NONE + 7: + func: FUNC_AND + def: SH2,NONE + delay: 0 + duration: 0 + andsw: NONE + 8: + func: FUNC_AND + def: L7,NONE + delay: 0 + duration: 3 + andsw: NONE + 10: + func: FUNC_STICKY + def: L11,NONE + delay: 0 + duration: 0 + andsw: NONE + 11: + func: FUNC_STICKY + def: L12,NONE + delay: 0 + duration: 0 + andsw: NONE + 12: + func: FUNC_OR + def: L11,L12 + delay: 0 + duration: 0 + andsw: NONE + 14: + func: FUNC_STICKY + def: L15,NONE + delay: 0 + duration: 0 + andsw: NONE + 15: + func: FUNC_STICKY + def: L16,NONE + delay: 0 + duration: 0 + andsw: NONE + 17: + func: FUNC_ADIFFEGREATER + def: Ail,6 + delay: 0 + duration: 0 + andsw: NONE + 18: + func: FUNC_ADIFFEGREATER + def: Ele,6 + delay: 0 + duration: 0 + andsw: NONE + 19: + func: FUNC_OR + def: L18,L19 + delay: 0 + duration: 0 + andsw: NONE + 20: + func: FUNC_STICKY + def: FM1,L20 + delay: 0 + duration: 0 + andsw: NONE + 22: + func: FUNC_VPOS + def: I3,90 + delay: 0 + duration: 0 + andsw: "!FM1" + 23: + func: FUNC_STICKY + def: FM1,L23 + delay: 0 + duration: 0 + andsw: NONE + 24: + func: FUNC_OR + def: L24,L13 + delay: 0 + duration: 0 + andsw: NONE + 25: + func: FUNC_AND + def: "!FM1,L24" + delay: 30 + duration: 0 + andsw: "!L23" + 27: + func: FUNC_OR + def: FM1,FM2 + delay: 0 + duration: 0 + andsw: NONE + 28: + func: FUNC_AND + def: L28,L16 + delay: 0 + duration: 0 + andsw: L8 + 29: + func: FUNC_AND + def: "!L29,L16" + delay: 0 + duration: 0 + andsw: L8 +customFn: + 0: + swtch: L2 + func: VARIO + 1: + swtch: L5 + func: PLAY_VALUE + def: TIMER2,10 + 2: + swtch: L26 + func: PLAY_TRACK + def: flapup,5 + 3: + swtch: L29 + func: LOGS + def: 10 + 4: + swtch: L30 + func: LOGS + def: 100 +swashR: + type: TYPE_NONE + value: 0 + collectiveSource: NONE + aileronSource: NONE + elevatorSource: NONE + collectiveWeight: 0 + aileronWeight: 0 + elevatorWeight: 0 +thrTraceSrc: Thr +switchWarningState: "" +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +potsWarnEnabled: 0 +displayChecklist: 0 +gvars: + 0: + name: Ail + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: Brk + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 2: + name: AiR + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 3: + name: Dif + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 4: + name: BkE + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 5: + name: Snp + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 6: + name: Ele + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 7: + name: Ail + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: Exp + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rssiAlarms: + disabled: 0 + warning: 0 + critical: 0 +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +screenData: + 0: + LayoutId: Layout1x1 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: Layout2x3 + layoutData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: outputs + 1: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: wing2 + 2: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_mix + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_ctr + 4: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: graph + 5: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: f3k_sw + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: name + 3: + widgetName: SoarETX + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: battery +view: 0 diff --git a/sdcard/c480x320/TEMPLATES/SoarETX/about.txt b/sdcard/c480x320/TEMPLATES/3.SoarETX/about.txt similarity index 100% rename from sdcard/c480x320/TEMPLATES/SoarETX/about.txt rename to sdcard/c480x320/TEMPLATES/3.SoarETX/about.txt diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt new file mode 100644 index 00000000..2f024356 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.txt @@ -0,0 +1 @@ +F3J Model (V-TAIL, 4 Servo Wings) \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml new file mode 100644 index 00000000..b3f421f0 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J VT_v2.yml @@ -0,0 +1,2243 @@ +semver: 2.9.1 +header: + name: "F3J VT_v2" + modelId: + 0: + val: 2 + bitmap: "ehawk.bmp" + labels: "glider" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" + 1: + start: 0 + swtch: "L20" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 50 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 0 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 0 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 1 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 1 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilR" + - + weight: -100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L31" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 23 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 45 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: -139 + symetrical: 0 + revert: 1 + curve: 0 + name: "Elev" + 2: + min: 0 + max: -510 + ppmCenter: 0 + offset: -160 + symetrical: 0 + revert: 1 + curve: 1 + name: "LftAil" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 490 + max: 0 + ppmCenter: 0 + offset: -10 + symetrical: 0 + revert: 1 + curve: 2 + name: "RgtAil" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -43 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: -50 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 50 + 19: + val: 100 + 20: + val: -71 + 21: + val: -42 + 22: + val: -21 + 23: + val: -2 + 24: + val: 20 + 25: + val: 100 + 26: + val: 77 + 27: + val: 56 + 28: + val: 37 + 29: + val: 18 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 59: + val: 100 + 61: + val: 100 + 62: + val: -100 + 63: + val: 100 + 64: + val: 100 + 65: + val: 90 + 166: + val: -50 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VPOS + def: "gv(8),0" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_VEQUAL + def: "gv(8),2" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_EDGE + def: "!L20,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_OR + def: "!L5,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_STICKY + def: "L22,L24" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "L25,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L29" + delay: 0 + duration: 0 + 30: + func: FUNC_STICKY + def: "L29,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_AND + def: "L31,!L29" + andsw: "!L30" + delay: 30 + duration: 0 + 33: + func: FUNC_AND + def: "L10,L19" + andsw: "NONE" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 3: + swtch: "L2" + func: VARIO + def: "" + 4: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 5: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER2,10" + 6: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 10: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 12: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 16: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 20: + swtch: "L22" + func: PLAY_TRACK + def: "fm-lch,1x" + 21: + swtch: "L32" + func: PLAY_TRACK + def: "flapup,5" + 22: + swtch: "L34" + func: LOGS + def: "50" + 23: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 24: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 25: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -42 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 0 + 2: + val: 20 + 3: + val: 0 + 4: + val: 11 + 5: + val: 0 + 6: + val: 150 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 4 + 2: + value: -128 + mode: 4 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L25" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L27" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -74 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 64,0 + channelsStart: 0 + channelsCount: 8 + failsafeMode: CUSTOM + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + receiverTelemetryOff: 0 + receiverHigherChannels: 0 + optionValue: 0 +failsafeChannels: + 0: + val: 45 + 1: + val: 143 + 2: + val: 115 + 3: + val: -32 + 4: + val: 32 + 5: + val: 43 + 9: + val: -1 + 10: + val: 32 + 11: + val: 32 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 272 + id2: + instance: 26 + label: "VSpd" + subId: 0 + type: TYPE_CUSTOM + unit: 5 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + id1: + id: 61699 + id2: + instance: 26 + label: "A2" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 2: + id1: + id: 256 + id2: + instance: 26 + label: "Alt" + subId: 0 + type: TYPE_CUSTOM + unit: 9 + prec: 1 + autoOffset: 1 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 61697 + id2: + instance: 24 + label: "RSSI" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + id1: + id: 65534 + id2: + instance: 248 + label: "TRSS" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + id1: + id: 65533 + id2: + instance: 248 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + id1: + id: 61700 + id2: + instance: 24 + label: "RxBt" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x000000 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0x000000 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f3j" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F3J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F3J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.txt new file mode 100644 index 00000000..5c4ae4b3 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.txt @@ -0,0 +1 @@ +F3J Model (4 Servo Wings) \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.yml new file mode 100644 index 00000000..1b24f8f5 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3J_v2.yml @@ -0,0 +1,2014 @@ +semver: 2.9.1 +header: + name: "F3J_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" + 1: + start: 0 + swtch: "L20" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L31" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 23 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 1 + name: "LftAil" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 2 + name: "RgtAil" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: -50 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 50 + 19: + val: 100 + 20: + val: -100 + 21: + val: -50 + 23: + val: 35 + 24: + val: 70 + 25: + val: -50 + 26: + val: -50 + 27: + val: -50 + 28: + val: -25 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 59: + val: 100 + 61: + val: 100 + 62: + val: -100 + 63: + val: 100 + 64: + val: 100 + 65: + val: 90 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VPOS + def: "gv(8),0" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_VEQUAL + def: "gv(8),2" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_EDGE + def: "!L20,0,-" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_OR + def: "!L5,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_STICKY + def: "L22,L24" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "L25,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L29" + delay: 0 + duration: 0 + 30: + func: FUNC_STICKY + def: "L29,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_AND + def: "L31,!L29" + andsw: "!L30" + delay: 30 + duration: 0 + 33: + func: FUNC_AND + def: "L10,L19" + andsw: "NONE" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 3: + swtch: "L2" + func: VARIO + def: "" + 4: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 5: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER2,10" + 6: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 10: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 12: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 16: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 20: + swtch: "L22" + func: PLAY_TRACK + def: "fm-lch,1x" + 21: + swtch: "L32" + func: PLAY_TRACK + def: "flapup,5" + 22: + swtch: "L34" + func: LOGS + def: "50" + 23: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 24: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 25: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 50 + 2: + val: 20 + 3: + val: 0 + 4: + val: 15 + 5: + val: -20 + 6: + val: 100 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 4 + 2: + value: 0 + mode: 4 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L25" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L27" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 2: + val: -438 + 3: + val: 435 + 4: + val: 1095 + 5: + val: 1014 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x000000 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0x000000 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f3j" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F3J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F3J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt new file mode 100644 index 00000000..6d75419e --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.txt @@ -0,0 +1 @@ +DLG model with rudder and elevator only. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml new file mode 100644 index 00000000..575c9920 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K RE_v2.yml @@ -0,0 +1,579 @@ +semver: 2.9.1 +header: + name: "F3K RE_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 0 + swtch: "L16" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "L15" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: GV7 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: S1 + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Dial" + offset: 0 +curves: + 31: + type: 0 + smooth: 0 + points: 0 + name: "Mem" +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + andsw: "L16" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "L7,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 4: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SD2,NONE" + andsw: "L1" + delay: 0 + duration: 0 + 6: + func: FUNC_OR + def: "SF2,L4" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_ADIFFEGREATER + def: "Ail,6" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_ADIFFEGREATER + def: "Ele,6" + andsw: "NONE" + delay: 0 + duration: 0 + 11: + func: FUNC_OR + def: "L10,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 12: + func: FUNC_STICKY + def: "FM1,L12" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_STICKY + def: "L15,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_STICKY + def: "L16,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 17: + func: FUNC_OR + def: "FM1,FM2" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_AND + def: "L18,L16" + andsw: "L8" + delay: 0 + duration: 0 + 19: + func: FUNC_AND + def: "!L19,L16" + andsw: "L8" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "L2" + func: VARIO + def: "" + 1: + swtch: "L5" + func: PLAY_VALUE + def: "TIMER2,10" + 2: + swtch: "L19" + func: LOGS + def: "10" + 3: + swtch: "L20" + func: LOGS + def: "100" + 4: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 5: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" +flightModeData: + 0: + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 0 + 5: + val: 0 + 6: + val: 100 + 7: + val: 0 + 8: + val: 50 + 1: + trim: + 0: + value: 40 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L7" + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 20 + mode: 1 + 1: + value: 20 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + name: "Zoom" + swtch: "L13" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 20 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 8: + val: 50 +thrTraceSrc: Thr +switchWarningState: +gvars: + 6: + name: "Ele" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Exp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Pokr" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "f3k" + 2: + type: String + value: + stringValue: "" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K_RE" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K_RE" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3K_RE" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K_RE" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt new file mode 100644 index 00000000..ca437ecf --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.txt @@ -0,0 +1 @@ +DLG model with "traditional" mixes, but the same features as the advanced F3K model. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml new file mode 100644 index 00000000..2f0677dc --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K TRAD_v2.yml @@ -0,0 +1,1177 @@ +semver: 2.9.1 +header: + name: "F3K TRAD_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 0 + swtch: "L16" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "L15" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -GV5 + destCh: 1 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 3 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 29 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 29 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L25" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 10 + destCh: 30 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 011001111 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 30 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV6 + destCh: 30 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "SnpFlp" + - + weight: GV2 + destCh: 31 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Brake" + - + weight: GV2 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Offset" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Camber" + - + weight: 100 + destCh: 31 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L11" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 1 + name: "Left" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 2 + name: "Right" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: GV7 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: GV8 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Align" + offset: 0 + curve: + type: 3 + value: 7 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: S1 + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Dial" + offset: 0 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "Lft" + 1: + type: 0 + smooth: 1 + points: 0 + name: "Rgt" + 2: + type: 0 + smooth: 0 + points: -2 + name: "BrF" + 3: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 4: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 5: + type: 1 + smooth: 0 + points: -2 + name: "DB" + 6: + type: 1 + smooth: 0 + points: 5 + name: "Aln" + 31: + type: 0 + smooth: 0 + points: 0 + name: "Mem" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: 50 + 12: + val: 100 + 13: + val: -100 + 14: + val: -100 + 17: + val: -50 + 19: + val: 100 + 21: + val: 100 + 22: + val: -100 + 23: + val: 100 + 24: + val: 100 + 25: + val: 90 + 26: + val: -100 + 27: + val: -100 + 28: + val: -50 + 29: + val: -50 + 32: + val: 50 + 33: + val: 50 + 34: + val: 100 + 35: + val: 100 + 36: + val: -75 + 37: + val: -75 + 38: + val: -25 + 39: + val: -25 + 40: + val: 25 + 41: + val: 25 + 42: + val: 75 + 43: + val: 75 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + andsw: "L16" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SD2,NONE" + andsw: "L1" + delay: 0 + duration: 0 + 6: + func: FUNC_OR + def: "SF2,L9" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_AND + def: "L7,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 10: + func: FUNC_STICKY + def: "L11,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 11: + func: FUNC_STICKY + def: "L12,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 12: + func: FUNC_OR + def: "L11,L12" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_STICKY + def: "L15,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_STICKY + def: "L16,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 17: + func: FUNC_ADIFFEGREATER + def: "Ail,6" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_ADIFFEGREATER + def: "Ele,6" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_OR + def: "L18,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 20: + func: FUNC_STICKY + def: "FM1,L20" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_VPOS + def: "I3,90" + andsw: "!FM1" + delay: 0 + duration: 0 + 23: + func: FUNC_STICKY + def: "FM1,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_OR + def: "L24,L13" + andsw: "NONE" + delay: 0 + duration: 0 + 25: + func: FUNC_AND + def: "!FM1,L24" + andsw: "!L23" + delay: 30 + duration: 0 + 27: + func: FUNC_AND + def: "FM2,L16" + andsw: "NONE" + delay: 0 + duration: 0 + 28: + func: FUNC_OR + def: "FM1,L28" + andsw: "L8" + delay: 0 + duration: 0 + 29: + func: FUNC_AND + def: "!L29,L16" + andsw: "L8" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "L2" + func: VARIO + def: "" + 1: + swtch: "L5" + func: PLAY_VALUE + def: "TIMER2,10" + 2: + swtch: "L26" + func: PLAY_TRACK + def: "flapup,5" + 3: + swtch: "L29" + func: LOGS + def: "10" + 4: + swtch: "L30" + func: LOGS + def: "100" + 5: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 6: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" + 7: + swtch: "FM4" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 66 + 1: + val: 67 + 2: + val: 10 + 3: + val: 0 + 4: + val: 12 + 5: + val: 25 + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 0 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: 0 + mode: 2 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L7" + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + name: "Zoom" + swtch: "L21" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 8 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "Brk" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "Ele" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Exp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 3: + val: "Brk" + 4: + val: "CbPS" + 5: + val: "Cmb" + 6: + val: "Aln" + 7: + val: "Pokr" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "f3k" + 2: + type: String + value: + stringValue: "" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing2" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "ailctr" + 2: + type: String + value: + stringValue: "F3K_TRAD" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K_TRAD" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 8 +modelRegistrationID: "-eC!U*U*" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.txt new file mode 100644 index 00000000..bbf15a78 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.txt @@ -0,0 +1,2 @@ +DLG model with advanced mixes. +Always full aileron control, as flaps are automatically retracted, if needed. Snap-flaps are compensated for camber preset, to avoid excessive movement. \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.yml new file mode 100644 index 00000000..7f3ba037 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F3K_v2.yml @@ -0,0 +1,1355 @@ +semver: 2.9.1 +header: + name: "F3K_v2" + bitmap: "" + labels: "" +timers: + 0: + start: 0 + swtch: "L16" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "L15" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Window" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -GV5 + destCh: 1 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 3 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Brake" + - + weight: 100 + destCh: 24 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L25" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 25 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "SnpNeg" + - + weight: 100 + destCh: 25 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: -4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 26 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "SnpPos" + - + weight: 100 + destCh: 26 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 27 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 011001111 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 27 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 28 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 3 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Flap" + - + weight: GV2 + destCh: 28 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Offset" + - + weight: 100 + destCh: 28 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "!L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 29 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AbsAil" + - + weight: 100 + destCh: 30 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "DwnExc" + - + weight: -100 + destCh: 30 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 31 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Flap" + - + weight: -100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 31 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L11" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" +limitData: + 0: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 1 + name: "Left" + 3: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 2 + name: "Right" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: GV7 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: GV8 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: GV9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Align" + offset: 0 + curve: + type: 3 + value: 7 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: S1 + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Dial" + offset: 0 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "Lft" + 1: + type: 0 + smooth: 1 + points: 0 + name: "Rgt" + 2: + type: 0 + smooth: 0 + points: -2 + name: "BrF" + 3: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 4: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 5: + type: 1 + smooth: 0 + points: -2 + name: "DB" + 6: + type: 1 + smooth: 0 + points: 5 + name: "Aln" + 31: + type: 0 + smooth: 0 + points: 0 + name: "Mem" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -50 + 8: + val: 50 + 9: + val: 100 + 10: + val: -100 + 11: + val: 50 + 12: + val: 100 + 13: + val: -100 + 14: + val: -100 + 17: + val: -50 + 19: + val: 100 + 21: + val: 100 + 22: + val: -100 + 23: + val: 100 + 24: + val: 100 + 25: + val: 90 + 26: + val: -100 + 27: + val: -100 + 28: + val: -50 + 29: + val: -50 + 32: + val: 50 + 33: + val: 50 + 34: + val: 100 + 35: + val: 100 + 36: + val: -75 + 37: + val: -75 + 38: + val: -25 + 39: + val: -25 + 40: + val: 25 + 41: + val: 25 + 42: + val: 75 + 43: + val: 75 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,NONE" + andsw: "L16" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SD2,NONE" + andsw: "L1" + delay: 0 + duration: 0 + 6: + func: FUNC_OR + def: "SF2,L9" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_AND + def: "L7,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 10: + func: FUNC_STICKY + def: "L11,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 11: + func: FUNC_STICKY + def: "L12,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 12: + func: FUNC_OR + def: "L11,L12" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_STICKY + def: "L15,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_STICKY + def: "L16,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 17: + func: FUNC_ADIFFEGREATER + def: "Ail,6" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_ADIFFEGREATER + def: "Ele,6" + andsw: "NONE" + delay: 0 + duration: 0 + 19: + func: FUNC_OR + def: "L18,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 20: + func: FUNC_STICKY + def: "FM1,L20" + andsw: "NONE" + delay: 0 + duration: 0 + 22: + func: FUNC_VPOS + def: "I3,90" + andsw: "!FM1" + delay: 0 + duration: 0 + 23: + func: FUNC_STICKY + def: "FM1,L23" + andsw: "NONE" + delay: 0 + duration: 0 + 24: + func: FUNC_OR + def: "L24,L13" + andsw: "NONE" + delay: 0 + duration: 0 + 25: + func: FUNC_AND + def: "!FM1,L24" + andsw: "!L23" + delay: 30 + duration: 0 + 27: + func: FUNC_OR + def: "FM1,FM2" + andsw: "NONE" + delay: 0 + duration: 0 + 28: + func: FUNC_AND + def: "L28,L16" + andsw: "L8" + delay: 0 + duration: 0 + 29: + func: FUNC_AND + def: "!L29,L16" + andsw: "L8" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "L2" + func: VARIO + def: "" + 1: + swtch: "L5" + func: PLAY_VALUE + def: "TIMER2,10" + 2: + swtch: "L26" + func: PLAY_TRACK + def: "flapup,5" + 3: + swtch: "L29" + func: LOGS + def: "10" + 4: + swtch: "L30" + func: LOGS + def: "100" + 5: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 6: + swtch: "FM3" + func: PLAY_TRACK + def: "speed,1x" + 7: + swtch: "FM4" + func: PLAY_TRACK + def: "therml,1x" +flightModeData: + 0: + trim: + 2: + value: -20 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 70 + 1: + val: 65 + 2: + val: 10 + 3: + val: 0 + 4: + val: 12 + 5: + val: 25 + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 1: + trim: + 0: + value: 0 + mode: 1 + 1: + value: -60 + mode: 2 + 2: + value: -20 + mode: 2 + 3: + value: 0 + mode: 1 + name: "Launch" + swtch: "L7" + fadeIn: 0 + fadeOut: 0 + 2: + trim: + 0: + value: 0 + mode: 1 + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 1 + name: "Zoom" + swtch: "L21" + fadeIn: 0 + fadeOut: 0 + 3: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: -40 + mode: 8 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 + gvars: + 6: + val: 100 + 7: + val: 100 + 8: + val: 50 +thrTraceSrc: Thr +switchWarningState: +gvars: + 0: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "Brk" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "Ele" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Ail" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Exp" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 6 + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +failsafeChannels: + 4: + val: 1024 + 5: + val: -1024 + 6: + val: -1024 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 3: + val: "Brk" + 4: + val: "CbPS" + 5: + val: "Cmb" + 6: + val: "Aln" + 7: + val: "Pokr" +potsWarnEnabled: 0 +screenData: + 0: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "f3k" + 2: + type: String + value: + stringValue: "FXX" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F3K" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing2" + 2: + type: String + value: + stringValue: "F3K" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F3K" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "ailctr" + 2: + type: String + value: + stringValue: "F3K" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F3K" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F3K" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "FXX" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "FXX" +view: 1 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.txt new file mode 100644 index 00000000..22dfe7be --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.txt @@ -0,0 +1 @@ +F5J Model (4 Servo Wings + Motor) \ No newline at end of file diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.yml b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.yml new file mode 100644 index 00000000..0bef2546 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/F5J_v2.yml @@ -0,0 +1,2382 @@ +semver: 2.9.1 +header: + name: "F5J_v2" + modelId: + 0: + val: 4 + bitmap: "" + labels: "" +timers: + 0: + start: 600 + swtch: "L19" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Flight" + 1: + start: 0 + swtch: "FM2" + value: 0 + mode: ON + countdownBeep: 0 + minuteBeep: 0 + persistent: 0 + countdownStart: -1 + showElapsed: 0 + extraHaptic: 0 + name: "Motor" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 1 +displayChecklist: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + weight: 100 + destCh: 0 + srcRaw: I0 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV3 + destCh: 0 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilRud" + - + weight: 100 + destCh: 1 + srcRaw: I1 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000100000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 1 + srcRaw: ch(21) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 2 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 2 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 3 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 3 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(31) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 4 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 5 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 5 + srcRaw: ch(29) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 6 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 8 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 8 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(0) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 50 + destCh: 9 + srcRaw: ch(1) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 10 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 11 + srcRaw: ch(30) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: I4 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 20 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L36" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkOff" + - + weight: 100 + destCh: 20 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 101111111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Adjust" + - + weight: GV5 + destCh: 21 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotEle" + - + weight: 10 + destCh: 21 + srcRaw: MAX + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotEle" + - + weight: -GV5 + destCh: 21 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BrkEle" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV5 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BEOffs" + - + weight: GV5 + destCh: 21 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "KAPOW" + - + weight: 100 + destCh: 22 + srcRaw: I5 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -50 + destCh: 22 + srcRaw: I3 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 50 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "MotCbr" + - + weight: 100 + destCh: 23 + srcRaw: ch(22) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -GV6 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Cbr-Sn" + - + weight: 100 + destCh: 23 + srcRaw: I1 + carryTrim: 1 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 7 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 10 + destCh: 24 + srcRaw: I6 + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -10 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 11 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Slider" + - + weight: 100 + destCh: 24 + srcRaw: ch(22) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 24 + srcRaw: ch(23) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 6 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV7 + destCh: 25 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 25 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV1 + destCh: 26 + srcRaw: I2 + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 10 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: -100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 27 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilUp" + - + weight: 100 + destCh: 28 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 100 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 28 + srcRaw: ch(26) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 0 + value: GV4 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilDow" + - + weight: 100 + destCh: 29 + srcRaw: ch(25) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: -100 + destCh: 29 + srcRaw: ch(27) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpDn" + - + weight: -100 + destCh: 29 + srcRaw: ch(28) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: 100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "BmpUp" + - + weight: 100 + destCh: 29 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 30 + srcRaw: ch(20) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + curve: + type: 3 + value: 5 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: ch(24) + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "NONE" + flightModes: 111011111 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 30 + srcRaw: I7 + carryTrim: 0 + mixWarn: 0 + mltpx: REPL + offset: 0 + swtch: "L13" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Align" + - + weight: 100 + destCh: 31 + srcRaw: ch(30) + carryTrim: 1 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 010000000 + curve: + type: 0 + value: -100 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" + - + weight: 100 + destCh: 31 + srcRaw: MAX + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: GV2 + destCh: 31 + srcRaw: I2 + carryTrim: 0 + mixWarn: 0 + mltpx: MUL + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "AilFlp" +limitData: + 0: + min: 550 + max: -550 + ppmCenter: 0 + offset: 44 + symetrical: 0 + revert: 1 + curve: 0 + name: "Rudd" + 1: + min: 0 + max: 0 + ppmCenter: 0 + offset: -88 + symetrical: 0 + revert: 0 + curve: 0 + name: "Elev" + 2: + min: 450 + max: -740 + ppmCenter: 0 + offset: -60 + symetrical: 0 + revert: 0 + curve: 1 + name: "LftAil" + 3: + min: 900 + max: -500 + ppmCenter: 0 + offset: 210 + symetrical: 0 + revert: 0 + curve: 3 + name: "LftFlp" + 4: + min: 500 + max: -930 + ppmCenter: 0 + offset: -220 + symetrical: 0 + revert: 0 + curve: 4 + name: "RgtFlp" + 5: + min: 780 + max: -370 + ppmCenter: 0 + offset: 89 + symetrical: 0 + revert: 0 + curve: 2 + name: "RgtAil" + 6: + min: 20 + max: -20 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Motor" + 8: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "LftV" + 9: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "RgtV" + 10: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 11: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CtrFlp" + 20: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Brake" + 21: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "EleMix" + 22: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "CbrPS" + 23: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "SnpFlp" + 24: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Camber" + 25: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 26: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AbsAil" + 27: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "UpExc" + 28: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "DnExc" + 29: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "FlpAil" + 30: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "Flap" + 31: + min: 0 + max: 0 + ppmCenter: 0 + offset: 0 + symetrical: 0 + revert: 0 + curve: 0 + name: "AilFlp" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Rud + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Rudder" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ele + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Elevat" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: Ail + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Ailero" + offset: 0 + curve: + type: 1 + value: 50 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 3 + swtch: "NONE" + flightModes: 110111111 + weight: 100 + name: "On" + offset: 0 + curve: + type: 3 + value: 9 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: -100 + name: "Off" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Brake" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: TrimThr + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 50 + name: "CambPs" + offset: 0 + curve: + type: 0 + value: -100 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: MAX + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Camber" + offset: 0 + - + mode: 3 + scale: 0 + trimSource: 1 + srcRaw: Thr + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "Adjust" + offset: 0 + curve: + type: 3 + value: 8 +curves: + 0: + type: 0 + smooth: 1 + points: 0 + name: "LA" + 1: + type: 0 + smooth: 1 + points: 0 + name: "RA" + 2: + type: 0 + smooth: 1 + points: 0 + name: "LF" + 3: + type: 0 + smooth: 1 + points: 0 + name: "RF" + 4: + type: 0 + smooth: 0 + points: 0 + name: "BrF" + 5: + type: 0 + smooth: 0 + points: 0 + name: "BrA" + 6: + type: 1 + smooth: 0 + points: -1 + name: "Snp" + 7: + type: 1 + smooth: 0 + points: 5 + name: "Adj" + 8: + type: 1 + smooth: 0 + points: -1 + name: "Mot" + 9: + type: 0 + smooth: 0 + points: -2 + name: "Abs" + 10: + type: 1 + smooth: 0 + points: -2 + name: "DB" +points: + 0: + val: -100 + 1: + val: -50 + 3: + val: 50 + 4: + val: 100 + 5: + val: -100 + 6: + val: -49 + 8: + val: 48 + 9: + val: 100 + 10: + val: -100 + 11: + val: -39 + 13: + val: 50 + 14: + val: 100 + 15: + val: -100 + 16: + val: -50 + 18: + val: 54 + 19: + val: 100 + 20: + val: -100 + 21: + val: -50 + 23: + val: 35 + 24: + val: 70 + 25: + val: 98 + 26: + val: 73 + 27: + val: 47 + 28: + val: 20 + 30: + val: -100 + 31: + val: -100 + 34: + val: -50 + 36: + val: -100 + 37: + val: -100 + 38: + val: -50 + 39: + val: -50 + 42: + val: 50 + 43: + val: 50 + 44: + val: 100 + 45: + val: 100 + 46: + val: -90 + 47: + val: -90 + 48: + val: -30 + 49: + val: -30 + 50: + val: 30 + 51: + val: 30 + 52: + val: 90 + 53: + val: 90 + 54: + val: -70 + 55: + val: 75 + 56: + val: 100 + 57: + val: 100 + 58: + val: 90 + 59: + val: 90 + 60: + val: 100 + 62: + val: 100 + 63: + val: -100 + 64: + val: 100 + 65: + val: 100 + 66: + val: 90 + 167: + val: -48 +logicalSw: + 0: + func: FUNC_AND + def: "!SA1,L19" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_AND + def: "SA2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_AND + def: "SB0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_AND + def: "SB2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "SC0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 5: + func: FUNC_AND + def: "SC2,!SC2" + andsw: "!FM2" + delay: 0 + duration: 0 + 6: + func: FUNC_AND + def: "SD0,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 7: + func: FUNC_AND + def: "SD2,L1" + andsw: "NONE" + delay: 0 + duration: 0 + 8: + func: FUNC_OR + def: "SF2,L11" + andsw: "NONE" + delay: 0 + duration: 0 + 9: + func: FUNC_AND + def: "SH2,NONE" + andsw: "NONE" + delay: 0 + duration: 0 + 10: + func: FUNC_AND + def: "L9,NONE" + andsw: "NONE" + delay: 0 + duration: 3 + 12: + func: FUNC_VEQUAL + def: "gv(7),1" + andsw: "NONE" + delay: 0 + duration: 0 + 13: + func: FUNC_VEQUAL + def: "gv(7),2" + andsw: "NONE" + delay: 0 + duration: 0 + 14: + func: FUNC_VEQUAL + def: "gv(7),3" + andsw: "NONE" + delay: 0 + duration: 0 + 15: + func: FUNC_VEQUAL + def: "gv(7),4" + andsw: "NONE" + delay: 0 + duration: 0 + 16: + func: FUNC_OR + def: "L13,L14" + andsw: "NONE" + delay: 0 + duration: 0 + 18: + func: FUNC_VEQUAL + def: "gv(8),1" + andsw: "NONE" + delay: 0 + duration: 0 + 20: + func: FUNC_AND + def: "!L9,!L26" + andsw: "NONE" + delay: 0 + duration: 0 + 21: + func: FUNC_EDGE + def: "!L5,0,-" + andsw: "L21" + delay: 0 + duration: 0 + 22: + func: FUNC_STICKY + def: "L22,L27" + andsw: "NONE" + delay: 0 + duration: 0 + 23: + func: FUNC_EDGE + def: "L9,0,-" + andsw: "L23" + delay: 0 + duration: 1 + 24: + func: FUNC_AND + def: "L24,!L30" + andsw: "!FM1" + delay: 0 + duration: 0 + 25: + func: FUNC_STICKY + def: "L25,L30" + andsw: "NONE" + delay: 0 + duration: 0 + 26: + func: FUNC_OR + def: "!L5,L26" + andsw: "NONE" + delay: 0 + duration: 0 + 27: + func: FUNC_OR + def: "!L5,L9" + andsw: "L26" + delay: 0 + duration: 0 + 28: + func: FUNC_VEQUAL + def: "TIMER2,30" + andsw: "NONE" + delay: 0 + duration: 0 + 29: + func: FUNC_OR + def: "L28,L29" + andsw: "NONE" + delay: 0 + duration: 0 + 31: + func: FUNC_VPOS + def: "Ele,90" + andsw: "L6" + delay: 0 + duration: 0 + 33: + func: FUNC_OR + def: "L26,L32" + andsw: "NONE" + delay: 0 + duration: 0 + 34: + func: FUNC_VPOS + def: "I4,90" + andsw: "!L34" + delay: 0 + duration: 0 + 35: + func: FUNC_STICKY + def: "L34,L35" + andsw: "NONE" + delay: 0 + duration: 0 + 36: + func: FUNC_AND + def: "L36,!L34" + andsw: "!L35" + delay: 30 + duration: 0 + 38: + func: FUNC_AND + def: "L10,FM2" + andsw: "L19" + delay: 0 + duration: 0 + 39: + func: FUNC_AND + def: "L10,!FM2" + andsw: "L19" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "ONE" + func: ADJUST_GVAR + def: "7,Cst,0,1" + 1: + swtch: "FM2" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 2: + swtch: "FM3" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 3: + swtch: "FM3" + func: HAPTIC + def: "0,1x" + 4: + swtch: "L2" + func: VARIO + def: "" + 5: + swtch: "L6" + func: PLAY_TRACK + def: "landin,1x" + 6: + swtch: "L7" + func: PLAY_VALUE + def: "TIMER1,10" + 7: + swtch: "L13" + func: ADJUST_GVAR + def: "0,Src,TrimRud,1" + 8: + swtch: "L13" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 9: + swtch: "L13" + func: ADJUST_GVAR + def: "2,Src,TrimAil,1" + 10: + swtch: "L13" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 11: + swtch: "L14" + func: ADJUST_GVAR + def: "1,Src,TrimThr,1" + 12: + swtch: "L14" + func: ADJUST_GVAR + def: "3,Src,TrimEle,1" + 13: + swtch: "L15" + func: ADJUST_GVAR + def: "0,Src,TrimAil,1" + 14: + swtch: "L15" + func: ADJUST_GVAR + def: "1,Src,TrimRud,1" + 15: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimEle,1" + 16: + swtch: "L15" + func: ADJUST_GVAR + def: "6,Src,TrimThr,1" + 17: + swtch: "L16" + func: ADJUST_GVAR + def: "2,Src,TrimRud,1" + 18: + swtch: "L16" + func: ADJUST_GVAR + def: "3,Src,TrimAil,1" + 19: + swtch: "L16" + func: ADJUST_GVAR + def: "4,Src,TrimEle,1" + 20: + swtch: "L16" + func: ADJUST_GVAR + def: "5,Src,TrimThr,1" + 21: + swtch: "!L23" + func: PLAY_TRACK + def: "disarm,!1x" + 22: + swtch: "L23" + func: PLAY_TRACK + def: "motarm,5" + 23: + swtch: "L24" + func: RESET + def: "Tmr2,1" + 24: + swtch: "L28" + func: PLAY_TRACK + def: "engoff,!1x" + 25: + swtch: "L37" + func: PLAY_TRACK + def: "flapup,5" + 26: + swtch: "L39" + func: LOGS + def: "5" + 27: + swtch: "L40" + func: LOGS + def: "10" + 28: + swtch: "FM4" + func: PLAY_TRACK + def: "speed,1x" + 29: + swtch: "FM5" + func: PLAY_TRACK + def: "therml,1x" + 30: + swtch: "FM0" + func: PLAY_TRACK + def: "cruise,1x" + 31: + swtch: "FM2" + func: PLAY_TRACK + def: "power,1x" +flightModeData: + 0: + trim: + 4: + value: 84 + mode: 0 + name: "Cruise" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 10 + 2: + val: 20 + 3: + val: 30 + 4: + val: 9 + 5: + val: 49 + 6: + val: 24 + 7: + val: 0 + 8: + val: 0 + 1: + trim: + 0: + value: 0 + mode: 31 + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + 3: + value: 0 + mode: 31 + name: "Adjust" + swtch: "L17" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + 4: + val: 1 + 6: + val: 70 + 2: + trim: + 2: + value: -40 + mode: 4 + name: "Motor" + swtch: "L26" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: 0 + 3: + trim: + 1: + value: 0 + mode: 31 + 2: + value: 0 + mode: 31 + name: "KAPOW" + swtch: "L32" + fadeIn: 0 + fadeOut: 0 + gvars: + 4: + val: -100 + 4: + trim: + 1: + value: 0 + mode: 1 + 2: + value: 0 + mode: 31 + name: "Speed" + swtch: "L3" + fadeIn: 0 + fadeOut: 0 + 5: + trim: + 1: + value: 54 + mode: 1 + 2: + value: -128 + mode: 10 + name: "Float" + swtch: "L4" + fadeIn: 0 + fadeOut: 0 +thrTraceSrc: Thr +switchWarningState: Hu +gvars: + 0: + name: "Ail" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "AiF" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 2: + name: "AiR" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 3: + name: "Dif" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 4: + name: "BkE" + min: 924 + max: 924 + popup: 0 + prec: 0 + unit: 0 + 5: + name: "Snp" + min: 974 + max: 1024 + popup: 0 + prec: 0 + unit: 0 + 6: + name: "CbA" + min: 1024 + max: 624 + popup: 0 + prec: 0 + unit: 0 + 7: + name: "Adj" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 8: + name: "Tmr" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +varioData: + source: 3 + centerSilent: 1 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 64,0 + channelsStart: 0 + channelsCount: 8 + failsafeMode: CUSTOM + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + receiverTelemetryOff: 0 + receiverHigherChannels: 0 + optionValue: 0 +failsafeChannels: + 0: + val: -45 + 1: + val: -90 + 2: + val: -61 + 3: + val: 20 + 4: + val: -9 + 5: + val: 91 + 6: + val: -1004 + 8: + val: -1 + 9: + val: -1 + 10: + val: 716 + 11: + val: 716 +trainerData: + mode: MASTER_TRAINER_JACK + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Rudd" + 1: + val: "Elev" + 2: + val: "Aile" + 3: + val: "Moto" + 4: + val: "Brk" + 5: + val: "CbPS" + 6: + val: "Cmb" + 7: + val: "Adj" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 61697 + id2: + instance: 24 + label: "RSSI" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + id1: + id: 65534 + id2: + instance: 248 + label: "TRSS" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 2: + id1: + id: 65533 + id2: + instance: 248 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 256 + id2: + instance: 26 + label: "Alt" + subId: 0 + type: TYPE_CUSTOM + unit: 9 + prec: 1 + autoOffset: 1 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + id1: + id: 61700 + id2: + instance: 24 + label: "RxBt" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 5: + id1: + id: 272 + id2: + instance: 26 + label: "VSpd" + subId: 0 + type: TYPE_CUSTOM + unit: 5 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + id1: + id: 61699 + id2: + instance: 26 + label: "A2" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 +screenData: + 0: + LayoutId: "Layout2P1" + layoutData: + zones: + 0: + widgetName: "ModelBmp" + widgetData: + options: + 0: + type: Color + value: + color: 0x105C98 + 2: + type: Bool + value: + boolValue: 0 + 3: + type: Color + value: + color: 0xE0ECF0 + 4: + type: Bool + value: + boolValue: 1 + 1: + widgetName: "Timer" + 2: + widgetName: "Timer" + widgetData: + options: + 0: + type: Unsigned + value: + unsignedValue: 1 + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 1: + LayoutId: "Layout2x3" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "outputs" + 2: + type: String + value: + stringValue: "F5J" + 1: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "wing4" + 2: + type: String + value: + stringValue: "F5J" + 2: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "mixes" + 2: + type: String + value: + stringValue: "F5J" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "brkcrv" + 2: + type: String + value: + stringValue: "F5J" + 4: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "graph" + 2: + type: String + value: + stringValue: "F5J" + 5: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "switch" + 2: + type: String + value: + stringValue: "F5J" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 + 2: + LayoutId: "Layout1x1" + layoutData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "f5j" + 2: + type: String + value: + stringValue: "" + options: + 0: + type: Bool + value: + boolValue: 1 + 1: + type: Bool + value: + boolValue: 1 + 2: + type: Bool + value: + boolValue: 1 + 3: + type: Bool + value: + boolValue: 1 + 4: + type: Bool + value: + boolValue: 0 +topbarData: + zones: + 0: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 1 + 1: + type: String + value: + stringValue: "name" + 2: + type: String + value: + stringValue: "FXX" + 3: + widgetName: "SoarETX" + widgetData: + options: + 0: + type: Signed + value: + signedValue: 2 + 1: + type: String + value: + stringValue: "battery" + 2: + type: String + value: + stringValue: "" +view: 3 +modelRegistrationID: "670112G-" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioThemesDisabled: GLOBAL +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/about.txt b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/about.txt new file mode 100644 index 00000000..fb318d02 --- /dev/null +++ b/sdcard/c480x320/TEMPLATES/4.SoarETX_v2/about.txt @@ -0,0 +1,4 @@ +A collection of sailplane templates with Lua widgets for timing, score keeping, graphing of log data, and model configuration. + +Author: Jesper Frickmann +Author: Frankie Arzu (v2) \ No newline at end of file diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/battery.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/battery.lua index 2e2d7d31..a0a10b95 100644 --- a/sdcard/c480x320/WIDGETS/SoarETX/1/battery.lua +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/battery.lua @@ -2,8 +2,8 @@ -- SoarETX, loadable component -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-02-17 -- --- Version: 1.0.0 -- +-- Date: 2022-11-21 -- +-- Version: 1.0.1 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -21,48 +21,7 @@ local widget, soarGlobals = ... --- Battery variables -local rxBatSrc -local rxBatNxtWarn = 0 - -local function getWarningLevel() - return 0.1 * (soarGlobals.getParameter(soarGlobals.batteryParameter) + 100) -end - -function widget.background() - local now = getTime() - - -- Receiver battery - if not rxBatSrc then - rxBatSrc = getFieldInfo("Cels") - if not rxBatSrc then rxBatSrc = getFieldInfo("RxBt") end - if not rxBatSrc then rxBatSrc = getFieldInfo("A1") end - if not rxBatSrc then rxBatSrc = getFieldInfo("A2") end - end - - if rxBatSrc then - soarGlobals.battery = getValue(rxBatSrc.id) - - if type(soarGlobals.battery) == "table" then - for i = 2, #soarGlobals.battery do - soarGlobals.battery[1] = math.min(soarGlobals.battery[1], soarGlobals.battery[i]) - end - soarGlobals.battery = soarGlobals.battery[1] - end - end - - -- Warn about low receiver battery or Rx off - if now > rxBatNxtWarn and soarGlobals.battery > 0 and soarGlobals.battery < getWarningLevel() then - playHaptic(200, 0, 1) - playFile("lowbat.wav") - playNumber(10 * soarGlobals.battery + 0.5, 1, PREC1) - rxBatNxtWarn = now + 2000 - end -end -- background() - function widget.refresh(event, touchState) - widget.background() - if event then lcd.exitFullScreen() end diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/brkcrv.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/brkcrv.lua new file mode 100644 index 00000000..071de004 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/brkcrv.lua @@ -0,0 +1,219 @@ +--------------------------------------------------------------------------- +-- SoarETX Adjust airbrake curves for flaps and ailerons -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-20 -- +-- Version: 1.0.2 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Airbrake curves" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 40 +local HEIGHT = 150 +local WIDTH = (LCD_W - 3 * DIST_X) / 2 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 +local TEXT_Y = BUTTON_Y + +-- Global variables +local INP_STEP = getFieldInfo("input8").id -- Step input for selecting curve point +local LS_STEP = 11 -- Set this LS to apply step input +local N = 5 -- Number of points on the curves +local MAX_Y = 100 -- Max plot value +local CRV_FLP = 4 -- Index of the flap curve +local CRV_AIL = 5 -- Index of the aileron curve +local tblFlp -- Table with data for the flap curve +local tblAil -- Table with data for the aileron curve +local activeP -- The point currently being edited +local stepOn = false -- Step input has be turned on by this widget + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if stepOn then + stepOn = false + setStickySwitch(LS_STEP, false) + end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +local function init() + tblFlp = GetCurve(CRV_FLP) + tblAil = GetCurve(CRV_AIL) + setStickySwitch(LS_STEP, true) + stepOn = true +end -- init() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjust a point, either on a curve or output +local function adjustPoint(crvIdx, crvTbl, slider) + crvTbl.y[activeP] = slider.value + model.setCurve(crvIdx, crvTbl) +end + +-- Reset curves to defaults +local function reset() + local ys = { -100, -50, 0, 25, 50 } + for i, y in ipairs(ys) do + tblFlp.y[i] = y + end + model.setCurve(CRV_FLP, tblFlp) + + ys = { -50, -50, -50, -25, 0 } + for i, y in ipairs(ys) do + tblAil.y[i] = y + end + model.setCurve(CRV_AIL, tblAil) +end +-------------------------------- Setup GUI -------------------------------- + +do + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + drawCurve(DIST_X, TOP, WIDTH, HEIGHT, tblFlp.y) + lcd.drawText(DIST_X + 2, TOP, "Flaps", SMLSIZE + colors.primary1) + + drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, tblAil.y) + lcd.drawText(WIDTH + 2 * DIST_X + 2, TOP, "Aileron", SMLSIZE + colors.primary1) + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + local flpSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_FLP, tblFlp, slider) end) + + function flpSlider.update() + flpSlider.value = tblFlp.y[activeP] + end + + local ailSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_AIL, tblAil, slider) end) + + function ailSlider.update() + ailSlider.value = tblAil.y[activeP] + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + stepOff() +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif not getLogicalSwitchValue(LS_STEP) then + init() + return + end + + activeP = math.floor((N - 1) / 2048 * (getValue(INP_STEP) + 1024) + 1.5) + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/f3k.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/f3k.lua index e431bc0d..7592147a 100644 --- a/sdcard/c480x320/WIDGETS/SoarETX/1/f3k.lua +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/f3k.lua @@ -2,8 +2,8 @@ -- SoarETX F3K score keeper, loadable component -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-03-08 -- --- Version: 1.0.0 -- +-- Date: 2023-01-23 -- +-- Version: 1.0.2 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -423,7 +423,7 @@ local function TargetTime() end elseif targetType == 3 then -- 1234 return Best1234Target(winTimer, scores, 4) - elseif targetType == 4 then -- Deuces + elseif targetType == 5 then -- Deuces if #scores == 0 then return math.max(0, math.floor(winTimer / 2)) elseif #scores == 1 then @@ -631,7 +631,7 @@ function libGUI.widgetRefresh() for i = 1, taskScores do lcd.drawText(COL1, y, string.format("%i.", i), colors.primary1 + DBLSIZE) if i > #scores then - lcd.drawText(COL2, y, " - - -", colors.primary1 + DBLSIZE) + lcd.drawText(COL2, y, "- - -", colors.primary1 + DBLSIZE) else lcd.drawTimer(COL2, y, scores[i], colors.primary1 + DBLSIZE) end @@ -873,7 +873,7 @@ do -- Setup practice tasks menu local taskData = { { 0, -1, 5, false, 0, 2, false }, -- Just fly { 0, -1, 5, false, 2, 2, true }, -- QR - { 600, 2, 2, true, 4, 2, false } -- Deuces + { 600, 2, 2, true, 5, 2, false } -- Deuces } -- Call back function running when a menu item is selected @@ -918,14 +918,14 @@ do -- Setup score keeper screen for F3K and Practice tasks local s = screenTask.timer(LEFT + 40, y, 60, HEIGHT, 0, nil) s.disabled = true - s.value = " - - -" + s.value = "- - -" screenTask.scores[i] = s -- Modify timer's draw function to insert score value local draw = s.draw function s.draw(idx) if i > #scores then - screenTask.scores[i].value = " - - -" + screenTask.scores[i].value = "- - -" else screenTask.scores[i].value = scores[i] end @@ -1124,7 +1124,7 @@ do -- Setup score browser screen lcd.drawText(x, y, j .. ".") if j > #record.scores then - lcd.drawText(x + 18, y, " - - -") + lcd.drawText(x + 18, y, "- - -") elseif record.unitStr == "s" then lcd.drawTimer(x + 18, y, record.scores[j]) else diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/f3kfh_mx.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/f3kfh_mx.lua new file mode 100644 index 00000000..c8568434 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/f3kfh_mx.lua @@ -0,0 +1,159 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K-FH configure mixes and battery warning -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-06-30 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Mixes & battery" +local fm = getFlightMode() + +-- Screen drawing constants +local LCD_W2 = LCD_W / 2 +local HEADER = 40 +local LINE = 32 +local HEIGHT = LINE - 4 +local MARGIN = 15 +local W1 = 170 +local W2 = LCD_W2 - 2 * MARGIN - W1 + +-------------------------------- Setup GUI -------------------------------- + +do + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Fligh mode + local fmIdx, fmStr = getFlightMode() + lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) + + -- Line stripes + for i = 1, 3, 2 do + lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) + end + + local bottom = HEADER + 5 * LINE + lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) + + -- Help text + local txt = "Some variables can be adjusted individually for each flight mode.\n" .. + "Therefore, select the flight mode for which you want to adjust.\n" .. + "You can change that behaviour under GLOBAL VARIABLES." + lcd.drawTextLines(MARGIN, bottom + 15, LCD_W - 2 * MARGIN, LCD_H - bottom, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Grid for items + local x, y = MARGIN, HEADER + 2 + + local function move() + if x == MARGIN then + x = x + LCD_W2 + else + x = MARGIN + y = y + LINE + end + end + + -- Add label and number element for a GV + local function addGV(label, gv, min, max) + gui.label(x, y, W1, HEIGHT, label) + + local function changeGV(delta, number) + local value = number.value + delta + value = math.max(value, min) + value = math.min(value, max) + model.setGlobalVariable(gv, fm, value) + return value + end + + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) + + function number.update() + number.value = model.getGlobalVariable(gv, fm) + end + + move() + end + + -- ADD GVs + addGV("Elevator input", 7, 20, 100) + addGV("Aileron input", 0, 10, 100) + addGV("Aileron " .. CHAR_RIGHT .. " flaps", 1, 0, 100) + addGV("Aileron " .. CHAR_RIGHT .. " rudder", 2, 0, 100) + addGV("Differential", 3, -100, 100) + addGV("Brake " .. CHAR_RIGHT .. " elevator", 4, 0, 40) + addGV("Snap - flap", 5, 0, 50) + addGV("Camber " .. CHAR_RIGHT .. " aileron", 6, 0, 200) + addGV("Exponential", 8, 0, 100) + + -- Add battery warning + gui.label(x, y, W1, HEIGHT, "Battery warning level (V)") + + local function changeBattery(delta, bat) + local value = bat.value + delta + value = math.max(0, value) + value = math.min(200, value) + soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) + return value + end + + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) + gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) +end -- Setup GUI + +function widget.background() +end -- background() + +function widget.refresh(event, touchState) + if not event then + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + end + + fm = getFlightMode() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/graph.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/graph.lua index 712baa9b..97bdc70e 100644 --- a/sdcard/c480x320/WIDGETS/SoarETX/1/graph.lua +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/graph.lua @@ -2,8 +2,8 @@ -- SoarETX graph of log data -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-03-20 -- --- Version: 1.0.0 -- +-- Date: 2022-08-28 -- +-- Version: 1.0.1 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -49,7 +49,7 @@ local FMAX = 1E38 local DEFAULT_PLOT = "Alt" local FIRST_EXCLUDED = "Rud" do - local lang = getGeneralSettings().language + local lang = getGeneralSettings().language if lang == "CZ" then FIRST_EXCLUDED = "Smer" elseif lang == "DE" then @@ -68,11 +68,15 @@ end -- Variables local gui local guiFile -local guiNoFiles +local guiPause local guiGraph local menu1 local menu2 +local buildingTree local fileTree +local fileCount +local getNextFileName +local fileName local data local refreshDates local lines @@ -92,32 +96,55 @@ local function timeSerial(str) end local function buildFileTree() - fileTree = { } - local count = 0 - - for fileName in dir("/LOGS") do + if not fileTree then + guiPause.title = "READING..." + gui = guiPause + fileTree = { } + fileCount = 0 + getNextFileName = dir("/LOGS") + fileName = getNextFileName() + end + + while fileName do + -- If there are many files, then we may run out of CPU instructions + if getUsage() > 90 then + return + end + if string.len(fileName) > 23 and string.sub(fileName, -4) == ".csv" then local dateStr = string.sub(fileName, -21, -12) - local nameStr = string.sub(fileName, -10, -9) .. ":" .. string.sub(fileName, -8, -7) .. ":" .. + local nameStr = string.sub(fileName, -10, -9) .. ":" .. string.sub(fileName, -8, -7) .. ":" .. string.sub(fileName, -6, -5) .. " " .. string.sub(fileName, 1, -23) if not fileTree[dateStr] then fileTree[dateStr] = { } + fileCount = fileCount + 1 end - + fileTree[dateStr][nameStr] = fileName - count = count + 1 end + + fileName = getNextFileName() end - - if count == 0 then - gui = guiNoFiles + + if getUsage() > 20 then + return + end + + getNextFileName = nil + fileName = nil + + if fileCount == 0 then + guiPause.title = "NO LOG FILES" + gui = guiPause headers = nil data = { } else refreshDates() gui = guiFile end + + buildingTree = false end local function readLines(fileName) @@ -160,7 +187,7 @@ local function readLines(fileName) headers[i] = field end end - + for i = 2, #headers do if string.sub(headers[i], 1, l) == DEFAULT_PLOT then plotIdx = i @@ -188,7 +215,7 @@ end local function readData() local plotIdxLast = #data[1] + 1 - + for i = #data - 1, #lines do if getUsage() > 90 then return @@ -231,14 +258,14 @@ end local function setupGUI(title) local gui = libGUI.newGUI() gui.title = title - + function gui.fullScreenRefresh() lcd.clear(COLOR_THEME_SECONDARY3) - + -- Top bar lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, gui.title, bit32.bor(DBLSIZE, colors.primary2)) - + -- Extra drawing gui.drawMore() end @@ -260,15 +287,16 @@ local function setupGUI(title) lcd.exitFullScreen() end end - + return gui end -- GUI to show if there are no log files -guiNoFiles = setupGUI("Graph") +guiPause = setupGUI("Graph") +guiPause.title = "" -function guiNoFiles.drawMore() - lcd.drawText(LCD_W / 2, LCD_H / 2, "NO LOG FILES", XXLSIZE + CENTER + VCENTER + colors.primary1) +function guiPause.drawMore() + lcd.drawText(LCD_W / 2, LCD_H / 2, guiPause.title, XXLSIZE + CENTER + VCENTER + colors.primary1) end -- GUI for selecting log file @@ -346,7 +374,7 @@ do cursor = #data end end - + -- Trap events with prompt when cursor is active local trapCursor = { run = function(event, touchState) @@ -423,7 +451,7 @@ do -- Background lcd.drawFilledRectangle(LFT, TOP, PLOT_W, PLOT_H, colors.primary2) lcd.drawRectangle(LFT, TOP, PLOT_W, PLOT_H, COLOR_THEME_SECONDARY2) - + if lines then local txt = "READING DATA" local flags = DBLSIZE + CENTER + VCENTER + colors.primary1 @@ -436,7 +464,7 @@ do lcd.drawText(LFT + PLOT_W / 2, TOP + PLOT_H / 2, txt, flags) return end - + -- Time scale xMin = data[2][1] local xRange = math.max(60, data[3][1] - xMin) @@ -537,6 +565,7 @@ end -- Setup guiGraph -------------------- Background and Refresh functions --------------------- function widget.background() + buildingTree = true fileTree = nil end -- background() @@ -548,12 +577,10 @@ function widget.refresh(event, touchState) widget.background() return end - - if not fileTree then + + if buildingTree then buildFileTree() - return end - + gui.run(event, touchState) end -- refresh(...) - diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/wing2.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/wing2.lua index 9efb734a..1526c149 100644 --- a/sdcard/c480x320/WIDGETS/SoarETX/1/wing2.lua +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/wing2.lua @@ -2,8 +2,8 @@ -- SoarETX flaperon alignment, loadable component -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-02-19 -- --- Version: 1.0.0 -- +-- Date: 2022-06-26 -- +-- Version: 1.0.2 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -39,11 +39,13 @@ local BUTTON_X = LCD_W - BUTTON_W - MARGIN local BUTTON_H = 36 local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 +-- Other constants local INP_STEP = getFieldInfo("input7").id -- Step input local LS_STEP = 10 -- Set this LS to apply step input and adjust local N = 5 -- Number of curve points local MAX_Y = 1500 -- Max output value local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels -- Flaperon curve indices local CRV_LFT = 0 @@ -64,10 +66,11 @@ local activeP -- The point currently being edited -- Make sure that we have the right number of points on the curve local function GetCurve(crvIndex) - local tbl = model.getCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) if #tbl.y ~= N then setStickySwitch(LS_STEP, false) + gui= nil error("Wrong number of points on curve CV" .. crvIndex + 1) end @@ -76,14 +79,14 @@ end -- GetCurve() -- Find the output where the specified curve index is being used local function GetOutput(crvIndex) - for i = 0, N - 1 do + for i = 0, NC - 1 do local out = model.getOutput(i) - + if out and out.curve == crvIndex then return i, out end end - + setStickySwitch(LS_STEP, false) error("No output channel with curve CV" .. crvIndex + 1) end -- GetOutput() @@ -93,13 +96,13 @@ local function init() lftOutIdx, lftOut = GetOutput(CRV_LFT) rgtCrv = GetCurve(CRV_RGT) rgtOutIdx, rgtOut = GetOutput(CRV_RGT) - setStickySwitch(LS_STEP, true) + setStickySwitch(LS_STEP, true) end -- init() -- Find index of the curve point that corresponds to the value of the step input local function FindPoint() local x = getValue(INP_STEP) - return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) end -- FindPoint() -- Compute output after applying curve and center/endpoints @@ -122,13 +125,13 @@ end local function drawCurve(x, y, w, h, yValues) -- Background and lines - gui.drawFilledRectangle(x, y, w, h, colors.primary2) - gui.drawRectangle(x, y, w, h, COLOR_THEME_SECONDARY2) + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) - + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) @@ -138,12 +141,12 @@ local function drawCurve(x, y, w, h, yValues) -- And now to the curve local xs = { } local ys = { } - + for i = 1, N do xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) end - + for i = 2, N do gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) end @@ -198,11 +201,11 @@ end local function sliderPoint(crvTbl, outTbl, reverse) local value local activeP = activeP - + if reverse then activeP = N + 1 - activeP end - + if activeP == 1 then value = outTbl.min elseif activeP == (N + 1) / 2 then @@ -212,7 +215,7 @@ local function sliderPoint(crvTbl, outTbl, reverse) else value = 10 * crvTbl.y[activeP] end - + if reverse then value = -value end @@ -221,9 +224,9 @@ local function sliderPoint(crvTbl, outTbl, reverse) end -- Reset outputs -local function reset(crv, crvIndex, out, outIndex) +local function reset() local midpt = (N + 1) / 2 - + for p = 1, N do local y = 200.0 / (N - 1) * (p - midpt) lftCrv.y[p] = y @@ -241,7 +244,7 @@ local function reset(crv, crvIndex, out, outIndex) rgtOut.offset = 0 rgtOut.max = 1000 model.setOutput(rgtOutIdx, rgtOut) - + init() end -- Reset() @@ -255,10 +258,10 @@ do lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) - -- Curves + -- Curves drawCurve(DIST_X, TOP, WIDTH, HEIGHT, lftYs) drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, rgtYs) - + -- Help text local txt = "Use the throttle stick to select a point on the\n" .. "curve, and adjust with the sliders on the screen.\n" .. @@ -283,19 +286,19 @@ do lcd.exitFullScreen() end end - + local lftSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjLft) function lftSlider.update() lftSlider.value = sliderPoint(lftCrv, lftOut, true) end - + local rgtSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjRgt) function rgtSlider.update() rgtSlider.value = sliderPoint(rgtCrv, rgtOut, false) end - + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) end -- Setup GUI @@ -318,7 +321,7 @@ function widget.refresh(event, touchState) init() return end - + activeP = FindPoint() ComputeYs(lftCrv, lftOut, lftYs) reverse(lftYs) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/1/wing4.lua b/sdcard/c480x320/WIDGETS/SoarETX/1/wing4.lua new file mode 100644 index 00000000..db35e1a0 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/1/wing4.lua @@ -0,0 +1,357 @@ +--------------------------------------------------------------------------- +-- SoarETX flaps and aileron alignment, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-20 -- +-- Version: 1.0.2 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Wing alignment" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 25 +local HEIGHT = 150 +local WIDTH = (LCD_W - 4.5 * DIST_X) / 4 +local TEXT_Y = 210 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 + +-- Other constants +local INP_STEP = getFieldInfo("input8").id -- Step input +local LS_STEP = 10 -- Set this LS to apply step input and adjust +local N = 5 -- Number of curve points +local MAX_Y = 1500 -- Max output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels + +-- Flaperon curve indices (LA, LF, RF, RA) +local CRV_IDX = { 0, 2, 3, 1 } +-- Tables with data for flaperon curves +local crvTbls = { {}, {}, {}, {} } +-- Indices of output channels +local outIds = { {}, {}, {}, {} } +-- Tables with data for flaperon output channels +local outTbls = { {}, {}, {}, {} } +-- Tables with y-values after both curve and output settings have been applied +local yVals = { {}, {}, {}, {} } +-- The point currently being edited +local activeP +-- Labels for curve plots +local labels = { + "Lft ail", + "Lft flp", + "Rgt flp", + "Rgt ail" +} +-- Step input has be turned on by this widget +local stepOn = false + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if stepOn then + stepOn = false + setStickySwitch(LS_STEP, false) + end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +-- Find the output where the specified curve index is being used +local function GetOutput(crvIndex) + for i = 0, NC - 1 do + local out = model.getOutput(i) + + if out and out.curve == crvIndex then + return i, out + end + end + + stepOff() + error("No output channel with curve CV" .. crvIndex + 1) +end -- GetOutput() + +local function init() + for i, j in ipairs(CRV_IDX) do + crvTbls[i] = GetCurve(j) + outIds[i], outTbls[i] = GetOutput(j) + end + + setStickySwitch(LS_STEP, true) + stepOn = true +end -- init() + +-- Find index of the curve point that corresponds to the value of the step input +local function FindPoint() + local x = getValue(INP_STEP) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) +end -- FindPoint() + +-- Compute output after applying curve and center/endpoints +local function ComputeYs() + for i, j in ipairs(CRV_IDX) do + local crv = crvTbls[i] + local out = outTbls[i] + local y = yVals[i] + + for p = 1, N do + if crv.y[p] < 0 then + y[p] = out.offset + 0.01 * crv.y[p] * (out.offset - out.min) + else + y[p] = out.offset + 0.01 * crv.y[p] * (out.max - out.offset) + end + end + + if i <= 2 then + -- Reverse curve points on the left side + for k = 1, math.floor((N + 1) / 2) do + y[k], y[N + 1 - k] = -y[N + 1 - k], -y[k] + end + end + end +end -- ComputeYs() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjustment is +/-750 around this offset +local function offset() + local ctr = (N + 1) / 2 + return (activeP - ctr) * 750 / (ctr - 1) +end + +-- Adjust a point, either on a curve or output +local function adjustPoint(i, slider) + local crvIdx = CRV_IDX[i] + local crvTbl = crvTbls[i] + local outIdx = outIds[i] + local outTbl = outTbls[i] + local activeP = activeP + local y = slider.value + offset() + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + y = -y + end + + if activeP == 1 then + outTbl.min = math.min(y, outTbl.offset - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == (N + 1) / 2 then + outTbl.offset = math.min(math.max(y, outTbl.min + MINDIF), outTbl.max - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == N then + outTbl.max = math.max(y, outTbl.offset + MINDIF) + model.setOutput(outIdx, outTbl) + else + crvTbl.y[activeP] = 0.1 * y + model.setCurve(crvIdx, crvTbl) + end +end + +-- The inverse function of adjust to set slider value from current settings +local function sliderPoint(i) + local crvTbl = crvTbls[i] + local outTbl = outTbls[i] + local activeP = activeP + local value + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + end + + if activeP == 1 then + value = outTbl.min + elseif activeP == (N + 1) / 2 then + value = outTbl.offset + elseif activeP == N then + value = outTbl.max + else + value = 10 * crvTbl.y[activeP] + end + + if i <= 2 then + value = -value + end + + return 10 * math.floor(0.1 * (value - offset()) + 0.5) +end + +-- Reset outputs +local function reset() + local midpt = (N + 1) / 2 + + for i, j in ipairs(CRV_IDX) do + local crvTbl = crvTbls[i] + for p = 1, N do + local y = 200.0 / (N - 1) * (p - midpt) + crvTbl.y[p] = y + end + model.setCurve(j, crvTbl) + + local outTbl = outTbls[i] + outTbl.min = -1000 + outTbl.offset = 0 + outTbl.max = 1000 + model.setOutput(outIds[i], outTbl) + end + + init() +end -- Reset() + +-------------------------------- Setup GUI -------------------------------- + +do + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + for i, j in ipairs(CRV_IDX) do + local x = (i - 1) * (DIST_X + WIDTH) + DIST_X + if i > 2 then + x = x - DIST_X / 2 + end + drawCurve(x, TOP, WIDTH, HEIGHT, yVals[i]) + lcd.drawText(x + 2, TOP, labels[i], SMLSIZE + colors.primary1) + end + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen.\n" .. + "First end points, then center, and finally +/-50%." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + for i, j in ipairs(CRV_IDX) do + local x = DIST_X / 2 + (i - 1) * (DIST_X + WIDTH) + if i > 2 then + x = x + WIDTH + DIST_X / 2 + end + local slider = gui.verticalSlider(x, TOP, HEIGHT, 0, -750, 750, 10, function(slider) adjustPoint(i, slider) end) + + function slider.update() + slider.value = sliderPoint(i) + end + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + stepOff() +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif not getLogicalSwitchValue(LS_STEP) then + init() + return + end + + activeP = FindPoint() + ComputeYs() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/ailctr.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/ailctr.lua new file mode 100644 index 00000000..434965ab --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/ailctr.lua @@ -0,0 +1,184 @@ +--------------------------------------------------------------------------- +-- SoarETX Center ailerons, loadable component -- +-- -- +-- Author: Jesper Frickmann +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Center ailerons" +local slider + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 20 +local TOP = HEADER + MARGIN +local SLIDER_X = LCD_W - 30 +local SLIDER_W = 50 +local SLIDER_H = 200 +local R2 = (LCD_H - TOP - MARGIN) / 1.707 +local R1 = R2 - 35 +local CTR_X = LCD_W / 2 +local CTR_Y = TOP + 0.707 * R2 +local SML_H = select(2, lcd.sizeText("", SMLSIZE)) + +-- Global variables +local GV_AIL = 0 -- Aileron travel +local GV_BRK = 1 -- Air brake travel +local GV_DIF = 3 -- Aileron differential + +-- Logical switch to disable camber etc. to center +local LS_CTR = 11 + +-- Special: blend two theme colors +local COLOR_BLEND +do + local c1 = lcd.getColor(COLOR_THEME_SECONDARY1) + local b1 = 8 * bit32.band(bit32.rshift(c1, 16), 0x1F) + local g1 = 4 * bit32.band(bit32.rshift(c1, 21), 0x3F) + local r1 = 8 * bit32.band(bit32.rshift(c1, 27), 0x1F) + + local c2 = lcd.getColor(COLOR_THEME_SECONDARY2) + local b2 = 8 * bit32.band(bit32.rshift(c2, 16), 0x1F) + local g2 = 4 * bit32.band(bit32.rshift(c2, 21), 0x3F) + local r2 = 8 * bit32.band(bit32.rshift(c2, 27), 0x1F) + + COLOR_BLEND = lcd.RGB((r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2) +end + +-- Draw radial line +local function drawRadian(deg) + deg = deg * math.pi / 180 + local x = CTR_X + R2 * math.sin(deg) + local y = CTR_Y - R2 * math.cos(deg) + lcd.drawLine(CTR_X, CTR_Y, x, y, SOLID, colors.primary3) +end + +-- Draw label on annulus +local function drawLabel(deg, r, txt, color) + deg = deg * math.pi / 180 + local x = CTR_X + r * math.sin(deg) + local y = CTR_Y - r * math.cos(deg) + lcd.drawText(x, y, txt, CENTER + VCENTER + SMLSIZE + color) +end + +-- Adjust global variables +local function adjust(slider) + -- Compensate for possible negative differential + local dif = model.getGlobalVariable(GV_DIF, 0) + local difComp = 100.0 / math.max(10.0, math.min(100.0, 100.0 + dif)) + -- Calculate aileron travel from current airbrake travel + local ail = math.min(2 * slider.value, 2 * (100 - slider.value) * difComp) + model.setGlobalVariable(GV_AIL, 0, ail) + model.setGlobalVariable(GV_BRK, 0, slider.value) +end + +-------------------------------- Setup GUI -------------------------------- + +do + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Illustration of flap and aileron travel + local ail = model.getGlobalVariable(GV_AIL, 0) + local ailDeg = 0.45 * ail + local brk = 2 * model.getGlobalVariable(GV_BRK, 0) + local brkDeg = 0.45 * brk + local dif = 0.01 * model.getGlobalVariable(GV_DIF, 0) + + lcd.drawPie(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 91 + brkDeg, colors.primary2) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 + ailDeg * math.min(1, 1 - dif), 90 + brkDeg, COLOR_THEME_SECONDARY2) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90, 90 + ailDeg * math.min(1, 1 - dif), COLOR_BLEND) + lcd.drawAnnulus(CTR_X, CTR_Y, R1, R2, 90 - ailDeg * math.min(1, 1 + dif), 90, COLOR_THEME_SECONDARY1) + + lcd.drawArc(CTR_X, CTR_Y, R2, 90 - ailDeg * math.min(1, 1 + dif), 90 + brkDeg, colors.primary3) + drawRadian(90 - ailDeg * math.min(1, 1 + dif)) + drawRadian(90) + drawRadian(90 + brkDeg) + + lcd.drawFilledCircle(CTR_X, CTR_Y, 2, colors.primary2) + lcd.drawCircle(CTR_X, CTR_Y, 3, colors.primary3) + lcd.drawCircle(CTR_X, CTR_Y, 2, colors.primary3) + + lcd.drawFilledCircle(CTR_X + R2, CTR_Y, 4, colors.edit) + lcd.drawCircle(CTR_X + R2, CTR_Y, 5, colors.primary3) + lcd.drawCircle(CTR_X + R2, CTR_Y, 4, colors.primary3) + + drawLabel(90 - ailDeg / 2 * math.min(1, 1 + dif), (R1 + R2) / 2, math.floor(ail * math.min(1, 1 + dif) + 0.5) .. "%", colors.primary2) + drawLabel(90 + math.min(brkDeg - 10, (ailDeg + brkDeg) / 2), (R1 + R2) / 2, math.floor(brk + 0.5) .. "%", colors.primary1) + lcd.drawText(CTR_X + R1, CTR_Y - SML_H, "aileron ", RIGHT + SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R1, CTR_Y, "brake ", RIGHT + SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R2, CTR_Y - SML_H, " max.", SMLSIZE + colors.primary1) + lcd.drawText(CTR_X + R2, CTR_Y, " reflex", SMLSIZE + colors.primary1) + + local txt = "Use the slider to adjust the flaperons to the position of maximum reflex.\n\n" .. + "Notice that camber can only move the flaperons down from this position." + lcd.drawTextLines(MARGIN, TOP, CTR_X - 2 * MARGIN, LCD_H - TOP - MARGIN, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + slider = gui.verticalSlider(SLIDER_X, TOP, SLIDER_H, 70, 50, 90, 1, adjust) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if getLogicalSwitchValue(LS_CTR) then + setStickySwitch(LS_CTR, false) + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif not getLogicalSwitchValue(LS_CTR) then + setStickySwitch(LS_CTR, true) + slider.value = model.getGlobalVariable(GV_BRK, 0) + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/battery.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/battery.lua new file mode 100644 index 00000000..a0a10b95 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/battery.lua @@ -0,0 +1,35 @@ +--------------------------------------------------------------------------- +-- SoarETX, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-11-21 -- +-- Version: 1.0.1 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... + +function widget.refresh(event, touchState) + if event then + lcd.exitFullScreen() + end + local flags = CENTER + VCENTER + MIDSIZE + if soarGlobals.battery and soarGlobals.battery > 0 then + flags = flags + COLOR_THEME_PRIMARY2 + else + flags = flags + COLOR_THEME_DISABLED + end + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, string.format("%1.1f V", soarGlobals.battery), flags) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/brkcrv.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/brkcrv.lua new file mode 100644 index 00000000..6f878131 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/brkcrv.lua @@ -0,0 +1,226 @@ +--------------------------------------------------------------------------- +-- SoarETX Adjust airbrake curves for flaps and ailerons -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = nil +local colors = libGUI.colors +local title = "Airbrake curves" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 40 +local HEIGHT = 150 +local WIDTH = (LCD_W - 3 * DIST_X) / 2 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 +local TEXT_Y = BUTTON_Y + +-- Global variables +local INP_STEP = getFieldInfo("input8").id -- Step input for selecting curve point +local LS_STEP = 11 -- Set this LS to apply step input +local N = 5 -- Number of points on the curves +local MAX_Y = 100 -- Max plot value +local CRV_FLP = 4 -- Index of the flap curve +local CRV_AIL = 5 -- Index of the aileron curve +local tblFlp -- Table with data for the flap curve +local tblAil -- Table with data for the aileron curve +local activeP -- The point currently being edited +local stepOn = false -- Step input has be turned on by this widget + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if stepOn then + stepOn = false + setStickySwitch(LS_STEP, false) + end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +local function init() + tblFlp = GetCurve(CRV_FLP) + tblAil = GetCurve(CRV_AIL) + setStickySwitch(LS_STEP, true) + stepOn = true +end -- init() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjust a point, either on a curve or output +local function adjustPoint(crvIdx, crvTbl, slider) + crvTbl.y[activeP] = slider.value + model.setCurve(crvIdx, crvTbl) +end + +-- Reset curves to defaults +local function reset() + local ys = { -100, -50, 0, 25, 50 } + for i, y in ipairs(ys) do + tblFlp.y[i] = y + end + model.setCurve(CRV_FLP, tblFlp) + + ys = { -50, -50, -50, -25, 0 } + for i, y in ipairs(ys) do + tblAil.y[i] = y + end + model.setCurve(CRV_AIL, tblAil) +end +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + + gui = libGUI.newGUI() + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + drawCurve(DIST_X, TOP, WIDTH, HEIGHT, tblFlp.y) + lcd.drawText(DIST_X + 2, TOP, "Flaps", SMLSIZE + colors.primary1) + + drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, tblAil.y) + lcd.drawText(WIDTH + 2 * DIST_X + 2, TOP, "Aileron", SMLSIZE + colors.primary1) + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + local flpSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_FLP, tblFlp, slider) end) + + function flpSlider.update() + flpSlider.value = tblFlp.y[activeP] + end + + local ailSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -100, 100, 1, function(slider) adjustPoint(CRV_AIL, tblAil, slider) end) + + function ailSlider.update() + ailSlider.value = tblAil.y[activeP] + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if (gui ~= nil) then + stepOff() + gui = nil + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = math.floor((N - 1) / 2048 * (getValue(INP_STEP) + 1024) + 1.5) + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/f3J.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/f3J.lua new file mode 100644 index 00000000..aa1533af --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/f3J.lua @@ -0,0 +1,351 @@ +--------------------------------------------------------------------------- +-- SoarETX F3J score keeper, loadable component -- +-- -- +-- Author: Frankie Arzu / Jesper Frickmann -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors + +-- GUIs for the different screens and popups +local screenTask = libGUI.newGUI() + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W)/2 +local BOT_ROW = LCD_H - 60 + +-- Constants +local LS_ALT = 0 -- LS1 allowing altitude calls +local LS_ALT10 = 7 -- LS8 for altitude calls every 10 sec. + +local LS_TRIGGER = 8 -- LS9 + +local GV_FLT_TMR = 8 -- GV8 for the flight timer +local FM_LAUNCH = 2 -- Launch flight mode + +-- Program states +local STATE_INITIAL = 0 -- Set flight time before the flight +local STATE_WINDOW = 1 -- Task window is active +local STATE_FLYING = 2 -- Flight timer is running +local STATE_LANDINGPTS = 3 -- Landed, input landing points +local STATE_TIME = 4 -- Input flight time +local STATE_SAVE = 5 -- Ready to save +local state -- Current program state + +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevTrig = false -- Previous vakue of Trigger +local prevWt -- Previous Window Time + +-- Other common variables +--local counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} -- Flight timer countdown +--local countIndex -- Index of timer count + +--local flightTimer -- Flight timer +local windowTimer -- Window Timer + +local callAlt = false + +local startHeight = 0 +local altTime = 0 +local landingPts = 0 + + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F3J Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + print("GotoState:"..newState) + + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state == STATE_INITIAL then + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + screenTask.labelInfo.title = "INITIAL" + screenTask.locked = false + + elseif state == STATE_WINDOW then + screenTask.labelInfo.title = "WINDOW" + screenTask.locked = true + + + elseif state == STATE_FLYING then + screenTask.labelInfo.title = "FLYING" + screenTask.locked = true + + elseif state == STATE_LANDINGPTS then + screenTask.labelInfo.title = "LANDED. Launch Alt ="..startHeight + + elseif state == STATE_TIME then + screenTask.labelInfo.title = "ENTER TIME" + + elseif state == STATE_SAVE then + screenTask.labelInfo.title = "SAVE DATA" + end + + -- Configure "button3" + --screenTask.button3.disabled = false + --screenTask.button3.title = "Button3" + + -- Configure info text label + --screenTask.labelInfo.title = " Info Label" +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName) + screenTask.title = taskName +end -- SetupTask(...) + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +local function TargetTime() + return model.getTimer(0).start +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + --countIndex = #counts + --while countIndex > 1 and counts[countIndex] >= targetTime do + -- countIndex = countIndex - 1 + --end + + -- Set Window timer + model.setTimer(0, { start = targetTime, value = targetTime }) + model.setTimer(1, { start = 0, value = 0 }) + + landingPts = 0 + startHeight = 100 -- default if no Alt + + GotoState(STATE_INITIAL) +end -- InitializeFlight() + + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + + local launchOn = (flightMode == FM_LAUNCH) and prevFM ~= flightMode -- Launch Activated + + local triggerNow = getLogicalSwitchValue(LS_TRIGGER) + prevTrig, triggerNow = triggerNow, triggerNow and not prevTrig + + prevFM = flightMode + + callAlt = (getLogicalSwitchValue(LS_ALT10)) -- Call alt every 10 sec. + + windowTimer = model.getTimer(0) -- Current motor timer value + flightTimer = model.getTimer(1) -- Current flight timer value + + if state == STATE_INITIAL then + landingPts = 0 + startHeight = 0 -- default if no Alt + + -- Move to Window Open + if triggerNow then + GotoState(STATE_WINDOW) + ResetAlt() + screenTask.labelInfo.title = "WINDOW OPEN" + + model.setGlobalVariable(GV_FLT_TMR, 0, 1) -- Wimdow Open + playTone(1760, 100, PLAY_NOW) + prevWt = model.getTimer(0).value + + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + end + + elseif state == STATE_WINDOW then + if triggerNow then -- Trigger switch released + GotoState(STATE_FLYING) + model.setGlobalVariable(GV_FLT_TMR, 0, 2) -- FLying + playTone(1760, 100, PLAY_NOW) + altTime = getTime() + 1000 + startHeight = getValue("Alt+") + end + + elseif state == STATE_FLYING then + if (launchOn) then -- Reflight + GotoState(STATE_WINDOW) + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + model.setTimer(1, { start = 0, value = 0 }) -- Flight Timer + return + end + + -- Record (and announce) start height + if altTime > 0 and getTime() > altTime then + startHeight = getValue("Alt+") + altTime = 0 + + -- Call launch height + if callAlt then + playNumber(startHeight, UNIT_METERS) + end + + if startHeight == 0 then startHeight = 100 end -- If no altimeter; default to 100 + end + + local wt = windowTimer.value -- Current window timer value + local cnt -- Count interval + + if wt > 120 then cnt = 60 + elseif wt >60 then cnt = 15 + elseif wt >10 then cnt = 5 + else cnt = 1 + end + + if math.ceil(prevWt / cnt) > math.ceil(wt / cnt) then + if wt > 10 then + playDuration(wt, 0) + elseif wt > 0 then + playNumber(wt, 0) + end + end + + -- Stop flight when the window expires + if wt <= 0 and prevWt > 0 then + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + end + + prevWt = wt + + if triggerNow and getTime() > altTime then + -- Stop timer and record scores + playTone(1760, 100, PLAY_NOW) + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + GotoState(STATE_LANDINGPTS) + end + + -- STATE_GLIDE + elseif state == STATE_LANDINGPTS then + if triggerNow then + GotoState(STATE_TIME) + end + elseif state == STATE_TIME then + if triggerNow then + GotoState(STATE_SAVE) + end + elseif state == STATE_SAVE then + if triggerNow then + InitializeFlight() + GotoState(STATE_INITIAL) + end + end + +end -- background() + + + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = (widget.zone.w / 2) - 198 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + -- Draw timers + local blink = 0 + local y = 1 + + local tmr = model.getTimer(0).value -- Window + if tmr < 0 and state > STATE_FLYING then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + + tmr = model.getTimer(1).value -- Flight Timer + lcd.drawText(COL3, y + 10, screenTask.labelTimer1.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) + y = y + 2 * dy + lcd.drawText(COL1, y , screenTask.labelInfo.title, colors.primary1 + DBLSIZE) +end -- widgetRefresh() + + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + --screenTask.run(event,touchState + libGUI.widgetRefresh() +end -- refresh(...) + +local function SetupScreenTask() + print("SetupScreenTask:Begin") + local y + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, " Info ", libGUI.flags + RIGHT) + + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Window:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.labelTimer1 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Flight:", MIDSIZE) + y = y + LINE2 + screenTask.timer1 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer1.disabled = true + print("SetupScreenTask:End") +end + + +-- Initialize stuff +SetupScreenTask() +SetupTask("10 Min Window") +InitializeFlight() diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/f3k.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/f3k.lua new file mode 100644 index 00000000..9ade9eae --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/f3k.lua @@ -0,0 +1,1265 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K score keeper, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors +local activeGUI + +-- GUIs for the different screens and popups +local menuMain = libGUI.newGUI() +local menuF3K = libGUI.newGUI() +local menuPractice = libGUI.newGUI() +local screenTask = libGUI.newGUI() +local promptSaveScores = libGUI.newGUI() +local menuScores = { } + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W)/2 +local BOT_ROW = LCD_H - 60 + +-- Input sources for the trim buttons +local trimSources = { + getFieldInfo("trim-ail").id, + getFieldInfo("trim-rud").id, + getFieldInfo("trim-ele").id, + getFieldInfo("trim-thr").id +} + +-- Constants +local LS_ALT = 0 -- LS allowing altitude calls +local LS_ALT10 = 5 -- LS for altitude calls every 10 sec. +local LS_WIN_TMR = 14 -- LS for the window timer +local LS_FLT_TMR = 15 -- LS for the flight timer + +local FM_LAUNCH = 1 -- Launch/motor flight mode + +-- Program states +local STATE_IDLE = 1 -- Task window not running +local STATE_PAUSE = 2 -- Task window paused, not flying +local STATE_FINISHED = 3 -- Task has been finished +local STATE_WINDOW = 4 -- Task window started, not flying +local STATE_READY = 5 -- Flight timer will be started when launch switch is released +local STATE_FLYING = 6 -- Flight timer started but flight not yet committed +local STATE_COMMITTED = 7 -- Flight timer started, and flight committed +local STATE_FREEZE = 8 -- Still committed, but freeze the flight timer +local state -- Current program state + +-- Common variables for score keeping +local scores = { } -- List of saved scores +local taskWindow = 0 -- Task window duration (zero counts up) +local launches = -1 -- Number of launches allowed, -1 for unlimited +local taskScores = 0 -- Number of scores in task +local finalScores = false -- Task scores are final +local targetType = 0 -- 1. Huge ladder, 2. Poker, 3. "1234", 4. Big ladder, Else: constant time +local scoreType -- 1. Best, 2. Last, 3. Make time +local totalScore -- Total score +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevWt -- Previous value of the window timer +local prevFt -- Previous value of flight timer + +-- Other common variables +local counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} -- Flight timer countdown +local countIndex -- Index of timer count +local nextCall = 0 -- Call out altitude every 10 sec. +local winTimer = 0 -- Window timer +local flightTimer -- Flight timer +local flightTime -- Flight flown + +-- Variables used for Poker task +local pokerCalled -- Lock in time in Poker task +local lastInput = 0 -- For announcing changes in PokerCall +local lastChange = 0 -- Same +local tblStep = { {30, 5}, {60, 10}, {120, 15}, {210, 30}, {420, 60} } -- Step sizes for input of call time + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F3K Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state < STATE_WINDOW or state == STATE_FREEZE then + setStickySwitch(LS_WIN_TMR, false) + setStickySwitch(LS_FLT_TMR, false) + screenTask.labelTimer0.title = "Target:" + screenTask.locked = false + + elseif state == STATE_WINDOW then + setStickySwitch(LS_WIN_TMR, true) + setStickySwitch(LS_FLT_TMR, false) + screenTask.labelTimer0.title = "Target:" + screenTask.locked = true + + elseif state == STATE_FLYING then + setStickySwitch(LS_WIN_TMR, true) + setStickySwitch(LS_FLT_TMR, true) + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + + if model.getTimer(0).start > 0 then + -- Report the target time + playDuration(model.getTimer(0).start, 0) + else + -- ... or beep + playTone(1760, 100, PLAY_NOW) + end + + elseif state == STATE_COMMITTED then + -- Call launch height + if getLogicalSwitchValue(LS_ALT) then + playNumber(getValue("Alt+"), UNIT_METERS) + end + + if launches > 0 then + launches = launches - 1 + end + + lastChange = 0 + + elseif state == STATE_FINISHED then + playTone(880, 1000, 0) + end + + -- Configure "button3" + screenTask.button3.disabled = false + if state <= STATE_PAUSE then + screenTask.button3.title = "Start" + elseif state == STATE_WINDOW then + screenTask.button3.title = "Pause" + elseif state >= STATE_COMMITTED then + screenTask.button3.title = "Zero" + else + screenTask.button3.disabled = true + end + + -- Configure info text label + if state == STATE_PAUSE then + screenTask.labelInfo.title = string.format("Total: %i sec.", totalScore) + elseif state == STATE_FINISHED then + screenTask.labelInfo.title = string.format("Done! %i sec.", totalScore) + else + if launches >= 0 then + local s = "" + if launches ~= 1 then s = "es" end + screenTask.labelInfo.title = string.format("%i launch%s left", launches, s) + else + screenTask.labelInfo.title = "" + end + end +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName, taskData) + screenTask.title = taskName + + taskWindow = taskData[1] + launches = taskData[2] + taskScores = taskData[3] + finalScores = taskData[4] + targetType = taskData[5] + scoreType = taskData[6] + screenTask.buttonQR.value = taskData[7] + scores = { } + totalScore = 0 + pokerCalled = false + + -- Setup scores + for i = 1, N_LINES do + if i > taskScores then + screenTask.scoreLabels[i].hidden = true + screenTask.scores[i].hidden = true + else + screenTask.scoreLabels[i].hidden = false + screenTask.scores[i].hidden = false + end + end + + -- A few extra counts in 1234 + if targetType == 3 then + counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45, 65, 70, 75, 125, 130, 135, 185, 190, 195} + else + counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} + end + + GotoState(STATE_IDLE) +end -- SetupTask(...) + +-- Keep the best scores +local function RecordBest(scores, newScore) + local n = #scores + local i = 1 + local j = 0 + + -- Find the position where the new score is going to be inserted + if n == 0 then + j = 1 + else + -- Find the first position where existing score is smaller than the new score + while i <= n and j == 0 do + if newScore > scores[i] then j = i end + i = i + 1 + end + + if j == 0 then j = i end -- New score is smallest; end of the list + end + + -- If the list is not yet full; let it grow + if n < taskScores then n = n + 1 end + + -- Insert the new score and move the following scores down the list + for i = j, n do + newScore, scores[i] = scores[i], newScore + end +end -- RecordBest (...) + +-- Used for calculating the total score and sometimes target time +local function MaxScore(iFlight) + if targetType == 1 then -- Huge ladder + return 60 + 120 * iFlight + elseif targetType == 2 then -- Poker + return 9999 + elseif targetType == 3 then -- 1234 + return 300 - 60 * iFlight + elseif targetType == 4 then -- Big ladder + return 30 + 30 * iFlight + else -- MaxScore = targetType + return targetType + end +end + +-- Record scores +local function Score() + if scoreType == 1 then -- Best scores + RecordBest(scores, flightTime) + + elseif scoreType == 2 then -- Last scores + local n = #scores + if n >= taskScores then + -- List is full; move other scores one up to make room for the latest at the end + for j = 1, n - 1 do + scores[j] = scores[j + 1] + end + else + -- List can grow; add to the end of the list + n = n + 1 + end + scores[n] = flightTime + + else -- Must make time to get score + local score = flightTime + -- Did we make time? + if flightTimer > 0 then + return + else + -- In Poker, only score the call + if pokerCalled then + score = model.getTimer(0).start + pokerCalled = false + end + end + scores[#scores + 1] = score + + end + + totalScore = 0 + for i = 1, #scores do + totalScore = totalScore + math.min(MaxScore(i), scores[i]) + end +end -- Score() + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +-- Find the best target time, given what has already been scored, as well as the remaining time of the window. +-- Note: maxTarget ensures that recursive calls to this function only test shorter target times. That way, we start with +-- the longest flight and work down the list. And we do not waste time testing the same target times in different orders. +local function Best1234Target(timeLeft, scores, maxTarget) + local bestTotal = 0 + local bestTarget = 0 + + -- Max. minutes there is time left to fly + local maxMinutes = math.min(maxTarget, 4, math.ceil(timeLeft / 60)) + + -- Iterate from 1 to n minutes to find the best target time + for i = 1, maxMinutes do + local target + local tl + local tot + local dummy + + -- Target in seconds + target = 60 * i + + -- Copy scores to a new table + local s = {} + for j = 1, #scores do + s[j] = scores[j] + end + + -- Add new target time to s; only until the end of the window + RecordBest(s, math.min(timeLeft, target)) + tl = timeLeft - target + + -- Add up total score, assuming that the new target time was made + if tl <= 0 or i == 1 then + -- No more flights are made; sum it all up + tot = 0 + for j = 1, math.min(4, #s) do + tot = tot + math.min(300 - 60 * j, s[j]) + end + else + -- More flights can be made; add more flights recursively + -- Subtract one second from tl for turnaround time + dummy, tot = Best1234Target(tl - 1, s, i - 1) + end + + -- Do we have a new winner? + if tot > bestTotal then + bestTotal = tot + bestTarget = target + end + end + + return bestTarget, bestTotal +end -- Best1234Target(..) + +-- Get called time from user in Poker +local function PokerCall() + local dial + + -- Find dials for setting target time in Poker and height ceilings etc. + for input = 0, 31 do + local tbl = model.getInput(input, 0) + + if tbl and tbl.name == "Dial" then + dial = tbl.source + end + end + + -- If input lines were not found, then default to S1 and S2 + if not dial then dial = getFieldInfo("s1").id end + + local input = getValue(dial) + local i, x = math.modf(1 + #tblStep * (math.min(1023, input) + 1024) / 2048) + local t1 = tblStep[i][1] + local t2 + if i >= #tblStep then + t2 = math.max(600, taskWindow) + 60 + else + t2 = tblStep[i + 1][1] + end + local dt = tblStep[i][2] + + local result = t1 + dt * math.floor(x * (t2 - t1) /dt) + + if scoreType == 3 then + result = math.min(winTimer - 1, result) + end + + if math.abs(input - lastInput) >= 20 then + lastInput = input + lastChange = getTime() + end + + if state == STATE_COMMITTED and lastChange > 0 and getTime() - lastChange > 100 then + playTone(3000, 100, PLAY_NOW) + playDuration(result) + lastChange = 0 + end + + return result +end -- PokerCall() + +local function TargetTime() + if targetType == 2 then -- Poker + if pokerCalled then + return model.getTimer(0).start + else + return PokerCall() + end + elseif targetType == 3 then -- 1234 + return Best1234Target(winTimer, scores, 4) + elseif targetType == 5 then -- Deuces + if #scores == 0 then + return math.max(0, math.floor(winTimer / 2)) + elseif #scores == 1 then + return math.max(0, math.min(winTimer, scores[1])) + else + return 0 + end + else -- All other tasks + return MaxScore(#scores + 1) + end +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + countIndex = #counts + while countIndex > 1 and counts[countIndex] >= targetTime do + countIndex = countIndex - 1 + end + + -- Set flight timer + model.setTimer(0, { start = targetTime, value = targetTime }) + flightTimer = targetTime + prevFt = targetTime +end -- InitializeFlight() + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + local launchPulled = (flightMode == FM_LAUNCH and prevFM ~= flightMode) + local launchReleased = (flightMode ~= prevFM and prevFM == FM_LAUNCH) + prevFM = flightMode + + -- Reset altitude + if launchPulled then + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + + ResetAlt() + end + + -- Call altitude every 10 sec. + if getLogicalSwitchValue(LS_ALT10) and now > nextCall then + playNumber(getValue("Alt"), UNIT_METERS) + nextCall = now + 1000 + end + + if state <= STATE_READY and state ~= STATE_FINISHED then + InitializeFlight() + end + + flightTimer = model.getTimer(0).value + flightTime = math.abs(model.getTimer(0).start - flightTimer) + winTimer = model.getTimer(1).value + + if state < STATE_WINDOW then + if state == STATE_IDLE then + -- Set window timer + model.setTimer(1, { start = taskWindow, value = taskWindow }) + winTimer = taskWindow + prevWt = taskWindow + + -- Automatically start window and flight if launch switch is released + if launchPulled then + GotoState(STATE_READY) + end + end + + else + -- Did the window expire? + if prevWt > 0 and winTimer <= 0 then + playTone(880, 1000, 0) + + if state < STATE_FLYING then + GotoState(STATE_FINISHED) + elseif screenTask.buttonEoW.value then + GotoState(STATE_FREEZE) + end + end + + if state == STATE_WINDOW then + if launchPulled then + GotoState(STATE_READY) + elseif launchReleased then + -- Play tone to warn that timer is NOT running + playTone(1760, 200, 0, PLAY_NOW) + end + + elseif state == STATE_READY then + if launchReleased then + GotoState(STATE_FLYING) + end + + elseif state >= STATE_FLYING then + -- Time counts + if flightTimer <= counts[countIndex] and prevFt > counts[countIndex] then + if flightTimer > 15 then + playDuration(flightTimer, 0) + else + playNumber(flightTimer, 0) + end + if countIndex > 1 then countIndex = countIndex - 1 end + elseif flightTimer > 0 and math.ceil(flightTimer / 60) < math.ceil(prevFt / 60) then + playDuration(flightTimer, 0) + end + + -- Blink when flight ttimer is negative + if flightTimer < 0 then + screenTask.timer0.blink = true + end + + if state == STATE_FLYING then + -- Within 10 sec. "grace period", cancel the flight + if launchPulled then + GotoState(STATE_WINDOW) + end + + -- After 10 seconds, commit flight + if flightTime >= 10 then + GotoState(STATE_COMMITTED) + end + + elseif launchPulled then + -- Report the time after flight is done + if model.getTimer(0).start == 0 then + playDuration(flightTime, 0) + end + + Score() + + -- Change state + if (finalScores and #scores == taskScores) or launches == 0 or (taskWindow > 0 and winTimer <= 0) then + GotoState(STATE_FINISHED) + elseif screenTask.buttonQR.value then + GotoState(STATE_READY) + else + GotoState(STATE_WINDOW) + end + end + end + + prevWt = winTimer + prevFt = flightTimer + end + + -- Update info for user dial targets + if state == STATE_COMMITTED and targetType == 2 and (scoreType ~= 3 or taskScores - #scores > 1) then + local call = PokerCall() + local min = math.floor(call / 60) + local sec = call - 60 * min + screenTask.labelInfo.title = string.format("Next call: %02i:%02i", min, sec) + end + + -- "Must make time" tasks + if scoreType == 3 then + if state == STATE_COMMITTED then + pokerCalled = true + elseif state < STATE_FLYING and state ~= STATE_FINISHED and winTimer < TargetTime() then + GotoState(STATE_FINISHED) + end + end +end -- background() + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + activeGUI.run(event, touchState) +end -- refresh(...) + +-- Push new GUI as sub screen +local function PushGUI(gui) + gui.previous = activeGUI + activeGUI = gui +end + +-- Are we allowed to pop screen? +local function CanPopGUI() + return activeGUI.previous and not activeGUI.editing and not activeGUI.locked +end + +-- Pop GUI to return to previous screen +local function PopGUI() + if CanPopGUI() then + activeGUI = activeGUI.previous + return true + end +end + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = widget.zone.w / 2 - 200 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + for i = 1, taskScores do + lcd.drawText(COL1, y, string.format("%i.", i), colors.primary1 + DBLSIZE) + if i > #scores then + lcd.drawText(COL2, y, "- - -", colors.primary1 + DBLSIZE) + else + lcd.drawTimer(COL2, y, scores[i], colors.primary1 + DBLSIZE) + end + y = y + dy + end + + -- Draw timers + local blink = 0 + local y = 4 + + local tmr = model.getTimer(0).value + if tmr < 0 and state == STATE_COMMITTED then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + tmr = model.getTimer(1).value + lcd.drawText(COL3, y + 10, "Task:", colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) +end -- widgetRefresh() + + +-- Setup screen with title, trims, flight mode etc. +local function SetupScreen(gui, title, pop) + gui.title = title + local x1 + + if pop then + x1 = LCD_W - 80 + else + x1 = LCD_W - 50 + end + + function gui.fullScreenRefresh() + local color + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, gui.title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Date + local now = getDateTime() + local str = string.format("%02i:%02i", now.hour, now.min) + lcd.drawText(x1, 6, str, RIGHT + MIDSIZE + colors.primary2) + + if soarGlobals.battery == 0 then + color = COLOR_THEME_DISABLED + else + color = colors.primary2 + end + + str = string.format("%1.1fV", soarGlobals.battery) + lcd.drawText(x1 - 65, 6, str, RIGHT + MIDSIZE + color) + + -- Draw trims + local p = { + { LCD_W - 191, LCD_H - 14, 177, 8 }, + { 14, LCD_H - 14, 177, 8 }, + { LCD_W - 14, 68, 8, 177 }, + { 7, 68, 8, 177 }, + } + + for i = 1, 4 do + local q = p[i] + local value = getValue(trimSources[i]) / 10.24 + local x, y + if q[3] > q[4] then + x = q[1] + q[3] * (value + 100) / 200 + y = q[2] + q[4] / 2 + else + x = q[1] + q[3] / 2 + y = q[2] + q[4] * (100 - value) / 200 + end + + lcd.drawFilledRectangle(q[1], q[2], q[3], q[4], COLOR_THEME_SECONDARY1) + lcd.drawFilledRectangle(x - 9, y - 6, 18, 15, colors.primary1) + lcd.drawFilledRectangle(x - 10, y - 7, 18, 15, colors.focus) + lcd.drawNumber(x, y, value, SMLSIZE + VCENTER + CENTER + colors.primary2) + end + + -- Flight mode + lcd.drawText(LCD_W / 2, LCD_H - LINE2, select(2, getFlightMode()), MIDSIZE + CENTER + COLOR_THEME_SECONDARY1) + end -- fullScreenRefresh() + + -- Return button + if pop then + gui.buttonRet = gui.custom({ }, LCD_W - 74, 6, 28, 28) + + function gui.buttonRet.draw(focused) + local color + + if CanPopGUI() then + color = colors.primary2 + gui.buttonRet.disabled = false + else + color = COLOR_THEME_DISABLED + gui.buttonRet.disabled = true + end + + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, color) + lcd.drawFilledRectangle(LCD_W - 61, 12, 3, 18, color) + for i = 0, 3 do + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, color) + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, color) + end + + if focused then + gui.buttonRet.drawFocus() + end + end + + function gui.buttonRet.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + PopGUI() + end + end + end + + -- Minimize button + local buttonMin = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonMin.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) + + if focused then + buttonMin.drawFocus() + end + end + + function buttonMin.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Short press EXIT to return to previous screen + local function HandleEXIT(event, touchState) + if PopGUI() then + return false + else + return event + end + end + gui.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) + + return gui +end -- SetupScreen + +-- Setup main menu +do + local WIDTH = 180 + local HEIGHT = 45 + local ROW = 65 + x = 40 + y = 60 + + SetupScreen(menuMain, "SoarETX F3K") + + -- Generate callbacks with closure for calling submenus + local function MakePush(subMenu) + return function() + PushGUI(subMenu) + end + end + + menuMain.button(x, y, WIDTH, HEIGHT, "F3K tasks", MakePush(menuF3K)) + y = y + ROW + menuMain.button(x, y, WIDTH, HEIGHT, "Practice", MakePush(menuPractice)) + y = y + ROW + menuMain.button(x, y, WIDTH, HEIGHT, "Scores", MakePush(menuScores)) + + activeGUI = menuMain +end + + +do -- Setup F3K tasks menu + SetupScreen(menuF3K, "F3K Tasks", true) + + local tasks = { + "A. Last flight", + "B. Two last 3:00", + "B. Two last 4:00", + "C. All up last down", + "D. Two flights only", + "E. Poker 10 min.", + "E. Poker 15 min.", + "F. Three best of six", + "G. Five best flights", + "H. 1-2-3-4 any order", + "I. Three best flights", + "J. Three last flights", + "K. Big Ladder", + "L. One flight only", + "M. Huge Ladder" + } + + -- {win, launches, scores, final, tgtType, scoType, QR } + local taskData = { + { 420, -1, 1, false, 300, 2, false }, -- A. Last flight + { 420, -1, 2, false, 180, 2, false }, -- B. Two last 3:00 + { 600, -1, 2, false, 240, 2, false }, -- B. Two last 4:00 + { 0, 5, 5, true, 180, 2, false }, -- C. AULD + { 600, 2, 2, true, 300, 2, true }, -- D. Two flights only + { 600, -1, 3, true, 2, 3, true }, -- E. Poker 10 min. + { 900, -1, 3, true, 2, 3, true }, -- E. Poker 15 min. + { 600, 6, 3, false, 180, 1, false }, -- F. 3 best of 6 + { 600, -1, 5, false, 120, 1, true }, -- G. 5 x 2:00 + { 600, -1, 4, false, 3, 1, true }, -- H. 1234 + { 600, -1, 3, false, 200, 1, true }, -- I. 3 Best + { 600, -1, 3, false, 180, 2, false }, -- J. 3 last + { 600, 5, 5, true, 4, 2, true }, -- K. Big ladder + { 600, 1, 1, true, 599, 2, false }, -- L. One flight only + { 900, 3, 3, true, 1, 2, true } -- M. Huge Ladder + } + + -- Call back function running when a menu item is selected + local function callBack(menu, event, touchState) + SetupTask(tasks[menu.selected], taskData[menu.selected]) + PushGUI(screenTask) + end + + menuF3K.menu(LEFT, TOP, LCD_W - 2 * LEFT, BOTTOM - TOP, tasks, callBack) +end + +do -- Setup practice tasks menu + SetupScreen(menuPractice, "Practice Tasks", true) + + local tasks = { + "Just Fly!", + "Quick Relaunch!", + "Deuces" + } + + -- {win, launches, scores, final, tgtType, scoType, QR } + local taskData = { + { 0, -1, 5, false, 0, 2, false }, -- Just fly + { 0, -1, 5, false, 2, 2, true }, -- QR + { 600, 2, 2, true, 5, 2, false } -- Deuces + } + + -- Call back function running when a menu item is selected + local function callBack(menu) + SetupTask(tasks[menu.selected], taskData[menu.selected]) + PushGUI(screenTask) + end + + menuPractice.menu(LEFT, TOP, LCD_W - 2 * LEFT, BOTTOM - TOP, tasks, callBack) +end + + +do -- Setup score keeper screen for F3K and Practice tasks + SetupScreen(screenTask, "", true) + + -- Restore default task and dismiss task screen + function screenTask.dismiss() + SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) + PopGUI() + end + + -- Return button shows prompt to save scores instead of popping right away + function screenTask.buttonRet.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + if state == STATE_IDLE then + screenTask.dismiss() + else + screenTask.showPrompt(promptSaveScores) + end + end + end + + -- Add score times + local y = TOP + local dy = select(2, lcd.sizeText("", libGUI.flags)) + + screenTask.scoreLabels = { } + screenTask.scores = { } + + for i = 1, N_LINES do + screenTask.scoreLabels[i] = screenTask.label(LEFT, y, 20, HEIGHT, string.format("%i.", i)) + + local s = screenTask.timer(LEFT + 40, y, 60, HEIGHT, 0, nil) + s.disabled = true + s.value = "- - -" + screenTask.scores[i] = s + + -- Modify timer's draw function to insert score value + local draw = s.draw + function s.draw(idx) + if i > #scores then + screenTask.scores[i].value = "- - -" + else + screenTask.scores[i].value = scores[i] + end + + draw(idx) + end + y = y + dy + end + + -- Add center buttons + local y = TOP + screenTask.buttonQR = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "QR", false, nil) + y = y + LINE + screenTask.buttonEoW = screenTask.toggleButton(COL2, y, BUTTON_W, HEIGHT, "EoW", true, nil) + + local function callBack(button) + if state <= STATE_PAUSE then + GotoState(STATE_WINDOW) + + elseif state == STATE_WINDOW then + GotoState(STATE_PAUSE) + + elseif state >= STATE_COMMITTED then + -- Record a zero score! + flightTime = 0 + Score() + + -- Change state + if winTimer <= 0 or (finalScores and #scores == taskScores) or launches == 0 then + GotoState(STATE_FINISHED) + else + playTone(440, 333, PLAY_NOW) + GotoState(STATE_WINDOW) + end + end + end + + y = y + LINE + screenTask.button3 = screenTask.button(COL2, y, BUTTON_W, HEIGHT, "Start", callBack) + + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, "", libGUI.flags + RIGHT) + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) + y = y + LINE2 + local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) + tmr.disabled = true + +-- Short press EXIT handler must prompt to save scores + local function HandleEXIT(event, touchState) + if CanPopGUI() then + screenTask.buttonRet.onEvent(EVT_VIRTUAL_ENTER) + return false + else + return event + end + end + screenTask.setEventHandler(EVT_VIRTUAL_EXIT, HandleEXIT) +end + +do -- Prompt asking to save scores and exit task window + local x0 = (LCD_W - PROMPT_W) / 2 + local y0 = (LCD_H - PROMPT_H) / 2 + local LEFT = x0 + PROMPT_M + local RGT = x0 + PROMPT_W - PROMPT_M + local TOP = y0 + PROMPT_M + local BOTTOM = y0 + PROMPT_H - PROMPT_M + + function promptSaveScores.fullScreenRefresh() + lcd.drawFilledRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary2) + lcd.drawRectangle(x0, y0, PROMPT_W, PROMPT_H, colors.primary1, 3) + end + + promptSaveScores.label(x0, TOP, PROMPT_W, HEIGHT, "Save scores?", libGUI.flags + CENTER) + + local function callBack(button) + if button == promptSaveScores.buttonYes then + local scoreFile = io.open(SCORE_FILE, "a") + if scoreFile then + io.write(scoreFile, string.format("%s,%s", model.getInfo().name, screenTask.title)) + + local now = getDateTime() + io.write(scoreFile, string.format(",%04i-%02i-%02i", now.year, now.mon, now.day)) + io.write(scoreFile, string.format(",%02i:%02i", now.hour, now.min)) + io.write(scoreFile, string.format(",s,%i", taskScores)) + io.write(scoreFile, string.format(",%i", totalScore)) + + for i = 1, #scores do + io.write(scoreFile, string.format(",%i", scores[i])) + end + + io.write(scoreFile, "\n") + io.close(scoreFile) + end + end + + -- Dismiss prompt and return to menu + screenTask.dismissPrompt() + screenTask.dismiss() + end -- callBack(...) + + promptSaveScores.buttonYes = promptSaveScores.button(LEFT, BOTTOM - HEIGHT, BUTTON_W, HEIGHT, "Yes", callBack) + promptSaveScores.button(RGT - BUTTON_W, BOTTOM - HEIGHT, BUTTON_W, HEIGHT, "No", callBack) + +end + +do -- Setup score browser screen + local RECORD_H = 58 -- Height of a record on the screen + local records -- Score records + local firstRecord -- First record on the screen + local scoreFile -- File handle + local pos -- Read position in file + local firstRecordTouch -- First record at the start of touch slide + + -- Read a line of a log file + local function ReadLine(scoreFile, pos) + if scoreFile and pos then + io.seek(scoreFile, pos) + local str = io.read(scoreFile, 100) + local endPos = string.find(str, "\n") + + if endPos then + pos = pos + endPos + str = string.sub(str, 1, endPos - 1) + return pos, str + end + end + + -- No "\n" was found; return nothing + return 0, "" + end -- ReadLine() + + -- Read a line a split comma separated fields + local function ParseLineData(str) + local i = 0 + local record = { } + record.scores = { } + + for field in string.gmatch(str, "[^,]+") do + i = i + 1 + + if i == 1 then + record.planeName = field + elseif i == 2 then + record.taskName = field + elseif i == 3 then + record.dateStr = field + elseif i == 4 then + record.timeStr = field + elseif i == 5 then + record.unitStr = field + elseif i == 6 then + record.taskScores = tonumber(field) + elseif i == 7 then + record.totalScore = tonumber(field) + else + record.scores[#record.scores + 1] = tonumber(field) + end + end + + if record.totalScore then + records[#records + 1] = record + end + end -- ReadLineData() + + local function DrawRecord(i, r) + local top = 40 + i * RECORD_H + local left = 200 + local w = (LCD_W - left - 10) / 3 + local record = records[r] + + if not record then + return + end + + if r % 2 == 0 then + lcd.drawFilledRectangle(0, top, LCD_W, RECORD_H, COLOR_THEME_SECONDARY2) + end + + lcd.drawText(10, top + 6, record.taskName, BOLD) + lcd.drawText(10, top + 24, record.dateStr .. " " .. record.timeStr, SMLSIZE) + lcd.drawText(10, top + 36, record.planeName, SMLSIZE) + + local x = left + local y = top + 6 + + for j = 1, math.min(5, record.taskScores) do + lcd.drawText(x, y, j .. ".") + + if j > #record.scores then + lcd.drawText(x + 18, y, "- - -") + elseif record.unitStr == "s" then + lcd.drawTimer(x + 18, y, record.scores[j]) + else + lcd.drawText(x + 18, y, record.scores[j] .. record.unitStr) + end + + if j == 3 then + x = left + y = top + 30 + else + x = x + w + end + end + + lcd.drawText(left + 2 * w, top + 30, "Total: " .. record.totalScore .. record.unitStr) + end -- DrawRecord + + function menuScores.run(event, touchState) + local color + local PROMPT_W = 300 + local PROMPT_H = 200 + + if not event then + return libGUI.widgetRefresh() + end + + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, "Score Card", bit32.bor(DBLSIZE, colors.primary2)) + + -- Date + local now = getDateTime() + local str = string.format("%02i:%02i", now.hour, now.min) + lcd.drawText(LCD_W - 80, 6, str, RIGHT + MIDSIZE + colors.primary2) + + if soarGlobals.battery == 0 then + color = COLOR_THEME_DISABLED + else + color = colors.primary2 + end + + str = string.format("%1.1fV", soarGlobals.battery) + lcd.drawText(LCD_W - 140, 6, str, RIGHT + MIDSIZE + color) + + -- Return button + lcd.drawFilledRectangle(LCD_W - 74, 6, 28, 28, COLOR_THEME_SECONDARY1) + lcd.drawRectangle(LCD_W - 74, 6, 28, 28, colors.primary2) + + for i = -1, 1 do + lcd.drawLine(LCD_W - 60 + i, 12, LCD_W - 60 + i, 30, SOLID, colors.primary2) + end + + for i = 0, 3 do + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 50 - i, 20, SOLID, colors.primary2) + lcd.drawLine(LCD_W - 60 , 10 + i, LCD_W - 70 + i, 20, SOLID, colors.primary2) + end + + -- Minimize button + lcd.drawFilledRectangle(LCD_W - 34, 6, 28, 28, COLOR_THEME_SECONDARY1) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawFilledRectangle(LCD_W - 30, 19, 20, 3, colors.primary2) + + if event ~= EVT_TOUCH_SLIDE then + firstRecordTouch = nil + end + + if event == EVT_VIRTUAL_EXIT then + firstRecord = nil + return PopGUI() + elseif event == EVT_TOUCH_TAP then + local x, y = touchState.x, touchState.y + + if 6 <= y and y <= 34 then + if LCD_W - 74 <= x and x <= LCD_W - 40 then + firstRecord = nil + return PopGUI() + elseif x >= LCD_W - 34 then + lcd.exitFullScreen() + end + end + end + + if firstRecord then + if event == EVT_VIRTUAL_PREV then + firstRecord = math.max(1, firstRecord - 1) + elseif event == EVT_VIRTUAL_NEXT then + firstRecord = math.max(1, math.min(#records - 3, firstRecord + 1)) + elseif event == EVT_TOUCH_SLIDE then + if not firstRecordTouch then + firstRecordTouch = firstRecord + end + local delta = math.floor((touchState.startY - touchState.y) / RECORD_H + 0.5) + firstRecord = math.max(1, math.min(#records - 3, firstRecordTouch + delta)) + end + + for i = 0, 3 do + local r = i + firstRecord + DrawRecord(i, r) + end + + else -- Read score records + lcd.drawText(LCD_W / 2, LCD_H / 2, "Reading scores ...", VCENTER + CENTER + DBLSIZE + colors.primary1) + + if not scoreFile then + scoreFile = io.open(SCORE_FILE, "r") + pos = 0 + if scoreFile then + records = { } + end + end + + if scoreFile then + for i = 1, 10 do + local str + pos, str = ReadLine(scoreFile, pos) + ParseLineData(str) + if pos == 0 then + io.close(scoreFile) + scoreFile = nil + firstRecord = math.max(1, #records - 3) + + if #records == 0 then + firstRecord = nil + end + + break + end + end + end + end + end -- run(...) +end + +-- Initialize stuff +SetupTask("Just Fly!", { 0, -1, 5, false, 0, 2, false }) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/f5J.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/f5J.lua new file mode 100644 index 00000000..9328898b --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/f5J.lua @@ -0,0 +1,392 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K score keeper, loadable component -- +-- -- +-- Author: Frankie Arzu/ Jesper Frickmann -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = DBLSIZE +local colors = libGUI.colors + +-- GUIs for the different screens and popups +local screenTask = libGUI.newGUI() + +-- Screen drawing constants +local HEADER = 40 +local LEFT = 40 +local RGT = LCD_W - 18 +local TOP = 50 +local BOTTOM = LCD_H - 30 +local LINE = 60 +local LINE2 = 28 +local HEIGHT = 42 +local HEIGHT2 = 18 +local BUTTON_W = 86 +local PROMPT_W = 260 +local PROMPT_H = 170 +local PROMPT_M = 30 +local N_LINES = 5 +local COL2 = (LCD_W - BUTTON_W)/2 +local BOT_ROW = LCD_H - 60 + +-- Constants +local LS_ALT = 0 -- LS1 allowing altitude calls +local LS_ALT10 = 7 -- LS8 for altitude calls every 10 sec. + +local LS_TRIGGER = 8 -- LS9 +local LS_ARM = 22 --LS23 + +local GV_FLT_TMR = 8 -- GV8 for the flight timer +local FM_LAUNCH = 2 -- Launch/motor flight mode + +-- Program states +local STATE_INITIAL = 0 -- Set flight time before the flight +local STATE_MOTOR= 1 -- Motor running +local STATE_GLIDE = 2 -- Gliding +local STATE_LANDINGPTS = 3 -- Landed, input landing points +local STATE_STARTHEIGHT = 4 -- Input start height +local STATE_TIME = 5 -- Input flight time +local STATE_SAVE = 6 -- Ready to save +local state -- Current program state + +local prevFM = getFlightMode() -- Used for detecting when FM changes +local prevFt -- Previous value of flight timer +local prevArm -- Previous value of Arm +local prevTrig = false -- Previous vakue of Trigger +local prevMt -- Previous Motor Time + +-- Other common variables +local counts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 45} -- Flight timer countdown +local countIndex -- Index of timer count + +local flightTimer -- Flight timer +local motorTimer -- Motor Timer + +local callAlt = false +local nextCall = 0 + +local prevCnt = 0 + +local startHeight = 0 +local offTime = 0 -- Motor Off time after Initial Climb +local landingPts = 0 + + +-- Browsing scores +local SCORE_FILE = "/LOGS/JF F5J Scores.csv" + +-- Handle transitions between program states +local function GotoState(newState) + print("GotoState:"..newState) + + state = newState + + -- Stop blinking + screenTask.timer0.blink = false + + if state == STATE_INITIAL then + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + screenTask.labelInfo.title = "INITIAL" + screenTask.labelTimer0.title = "Target:" + screenTask.locked = false + + elseif state == STATE_MOTOR then + screenTask.labelInfo.title = "MOTOR" + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + + elseif state == STATE_GLIDE then + screenTask.labelInfo.title = "GLIDE" + model.setGlobalVariable(GV_FLT_TMR, 0, 1) + screenTask.labelTimer0.title = "Flight:" + screenTask.locked = true + elseif state == STATE_LANDINGPTS then + screenTask.labelInfo.title = "LANDED. Launch Alt ="..startHeight + playTone(880, 1000, 0) + model.setGlobalVariable(GV_FLT_TMR, 0, 0) + + elseif state == STATE_SAVE then + screenTask.labelInfo.title = "SAVE DATA" + end + + -- Configure "button3" + --screenTask.button3.disabled = false + --screenTask.button3.title = "Button3" + + -- Configure info text label + --screenTask.labelInfo.title = " Info Label" +end -- GotoState() + +-- Function for setting up a task +local function SetupTask(taskName) + screenTask.title = taskName +end -- SetupTask(...) + +-- Reset altimeter +local function ResetAlt() + for i = 0, 31 do + if model.getSensor(i).name == "Alt" then + model.resetSensor(i) + break + end + end +end + +local function TargetTime() + return model.getTimer(0).start +end -- TargetTime() + +-- Initialize variables before flight +local function InitializeFlight() + local targetTime = TargetTime() + + -- Get ready to count down + countIndex = #counts + while countIndex > 1 and counts[countIndex] >= targetTime do + countIndex = countIndex - 1 + end + + -- Set flight timer + model.setTimer(0, { start = targetTime, value = targetTime }) + flightTimer = targetTime + prevFt = targetTime + + landingPts = 0 + startHeight = 100 -- default if no Alt + + GotoState(STATE_INITIAL) +end -- InitializeFlight() + + +function widget.background() + local now = getTime() + local flightMode = getFlightMode() + + local cnt -- Count interval + local motorOn = (flightMode == FM_LAUNCH) -- Motor running + local armedNow = getLogicalSwitchValue(LS_ARM) + local triggerNow = getLogicalSwitchValue(LS_TRIGGER) + + prevArm, armedNow = armedNow, armedNow and not prevArm + prevTrig, triggerNow = triggerNow, triggerNow and not prevTrig + + callAlt = (getLogicalSwitchValue(LS_ALT10)) -- Call alt every 10 sec. + + flightTimer = model.getTimer(0) -- Current flight timer value + motorTimer = model.getTimer(1) -- Current motor timer value + + if armedNow and state ~= STATE_INITIAL then + GotoState(STATE_INITIAL) + end + + if state == STATE_INITIAL then + landingPts = 0 + startHeight = 100 -- default if no Alt + + -- Reset altitude if the motor was armed now + if armedNow then + ResetAlt() + screenTask.labelInfo.title = "MOTOR ARMED" + if soarGlobals.battery == 0 then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + end + end + + if motorOn then + GotoState(STATE_MOTOR) + prevMt = flightTimer.value + offTime = 0 + end + + elseif state == STATE_MOTOR then + local mt = motorTimer.value -- Current motor timer value + local sayt -- Timer value to announce (we don't have time to say "twenty-something") + + if mt <= 20 then cnt = 5; sayt = mt + elseif mt < 30 then cnt = 1; sayt = mt - 20 + else cnt = 1; sayt = mt + end + + if math.floor(prevMt / cnt) < math.floor(mt / cnt) then + playNumber(sayt, 0) + end + + prevMt = mt + + if not motorOn then -- Motor stopped; start 10 sec. count and record start height + if offTime == 0 then + offTime = now; prevCnt = 1 + end + + if triggerNow then -- Trigger switch released + prevFt = flightTimer.value + end + GotoState(STATE_GLIDE) + end + + elseif state == STATE_GLIDE then + local ft = flightTimer.value + + -- Count down flight time + if ft > 120 then cnt = 60 + elseif ft >60 then cnt = 15 + elseif ft >10 then cnt = 5 + else cnt = 1 + end + + if math.ceil(prevFt / cnt) > math.ceil(ft / cnt) then + if ft > 10 then + playDuration(ft, 0) + elseif ft > 0 then + playNumber(ft, 0) + end + end + + prevFt = ft + + if offTime > 0 then + -- 10 sec. count after motor off + cnt = math.floor((now - offTime) / 100) + + if cnt > prevCnt then + prevCnt = cnt + + if cnt >= 10 then + offTime = 0 -- No more counts + + -- Time to record start height + local alt = getValue("Alt+") + if alt > 0 then + startHeight = alt + end + + -- Call launch height + if callAlt then + playNumber(alt, UNIT_METERS) + else + playNumber(cnt, 0) + end + else + playNumber(cnt, 0) + end + end + else + -- Call altitude every 10 sec. + if callAlt and now > nextCall then + playNumber(getValue("Alt"), UNIT_METERS) + nextCall = now + 1000 + end + end + + if triggerNow then + -- Stop timer and record scores + GotoState(STATE_LANDINGPTS) + model.setTimer(0, {value = flightTimer.start - flightTimer.value}) + playDuration(flightTimer.start - flightTimer.value) + end + -- STATE_GLIDE + elseif state == STATE_LANDINGPTS then + if triggerNow then + GotoState(STATE_SAVE) + end + elseif state == STATE_SAVE then + if triggerNow then + GotoState(STATE_INITIAL) + end + end + + + -- Motor restart; score a zero + if (state == STATE_GLIDE or state == STATE_LANDINGPTS) and motorOn then + state = STATE_SAVE + model.setTimer(0, {value = 0}) + startHeight = 0 + end +end -- background() + + + +-- Draw zone area when not in fullscreen mode +function libGUI.widgetRefresh() + local COL1 = (widget.zone.w / 2) - 198 + local COL2 = COL1 + 30 + local COL3 = COL1 + 125 + local RGT = COL1 + 400 + + -- Draw scores + x = 5 + local y = 0 + local dy = widget.zone.h / N_LINES + + -- Draw timers + local blink = 0 + local y = 1 + + local tmr = model.getTimer(0).value -- Flight + if tmr < 0 and state > STATE_GLIDE then + blink = BLINK + end + + lcd.drawText(COL3, y + 10, screenTask.labelTimer0.title, colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + blink + XXLSIZE + RIGHT) + y = y + 2 * dy + tmr = model.getTimer(1).value -- Motor + lcd.drawText(COL3, y + 10, "Motor:", colors.primary1 + DBLSIZE) + lcd.drawTimer(RGT, y, tmr, colors.primary1 + XXLSIZE + RIGHT) + y = y + 2 * dy + lcd.drawText(COL1, y , screenTask.labelInfo.title, colors.primary1 + DBLSIZE) +end -- widgetRefresh() + + +-- Refresh function +function widget.refresh(event, touchState) + widget.background() + --screenTask.run(event,touchState + libGUI.widgetRefresh() +end -- refresh(...) + +local function SetupScreenTask() + print("SetupScreenTask:Begin") + local y + -- Info text label + screenTask.labelInfo = screenTask.label(RGT - 250, BOT_ROW, 250, HEIGHT, " Info ", libGUI.flags + RIGHT) + + + -- Add timers + y = TOP + screenTask.labelTimer0 = screenTask.label(RGT - 160, y, 50, HEIGHT2, "Target:", MIDSIZE) + y = y + LINE2 + screenTask.timer0 = screenTask.timer(RGT - 160, y, 160, HEIGHT, 0, nil, XXLSIZE + RIGHT) + screenTask.timer0.disabled = true + + y = y + LINE + screenTask.label(RGT - 160, y, 50, HEIGHT2, "Task:", MIDSIZE) + y = y + LINE2 + local tmr = screenTask.timer(RGT - 160, y, 160, HEIGHT, 1, nil, XXLSIZE + RIGHT) + tmr.disabled = true + print("SetupScreenTask:End") +end + + +-- Initialize stuff +SetupScreenTask() +SetupTask("10 Min Window") +InitializeFlight() diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/graph.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/graph.lua new file mode 100644 index 00000000..97bdc70e --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/graph.lua @@ -0,0 +1,586 @@ +--------------------------------------------------------------------------- +-- SoarETX graph of log data -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-08-28 -- +-- Version: 1.0.1 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- +local widget, soarGlobals = ... + +local libGUI = loadGUI() +libGUI.flags = 0 +local colors = libGUI.colors +local title = "Graph" + +-- Screen drawing constants +local LCD_W2 = LCD_W / 2 +local HEADER = 40 +local TOP = 50 +local BOTTOM = LCD_H - 18 +local LINE = 40 +local HEIGHT = 28 +local LFT = 30 +local WIDTH = 60 +local W1 = 0.4 * (LCD_W - 3 * LFT) +local W2 = (LCD_W - 3 * LFT) - W1 +local COL2 = W1 + 2 * LFT +local PLOT_W = LCD_W - 3 * LFT - WIDTH +local PLOT_H = BOTTOM - TOP +local RGT = LFT + PLOT_W +local MARGIN = 10 +local BUTTON_X = RGT + MARGIN +local BUTTON_W = LCD_W - BUTTON_X - MARGIN + +-- Other constants +local FMAX = 1E38 +local DEFAULT_PLOT = "Alt" +local FIRST_EXCLUDED = "Rud" +do + local lang = getGeneralSettings().language + if lang == "CZ" then + FIRST_EXCLUDED = "Smer" + elseif lang == "DE" then + FIRST_EXCLUDED = "Sei" + elseif lang == "FR" or lang == "IT" then + FIRST_EXCLUDED = "Dir" + elseif lang == "PL" then + FIRST_EXCLUDED = "SK" + elseif lang == "PT" then + FIRST_EXCLUDED = "Lem" + elseif lang == "SE" then + FIRST_EXCLUDED = "Rod" + end +end + +-- Variables +local gui +local guiFile +local guiPause +local guiGraph +local menu1 +local menu2 +local buildingTree +local fileTree +local fileCount +local getNextFileName +local fileName +local data +local refreshDates +local lines +local cursor +local xMin +local xScale +local y0 +local yScale + +------------------------------- Reading data ------------------------------ + +local function timeSerial(str) + local hr = string.sub(str, 1, 2) + local mn = string.sub(str, 4, 5) + local sc = string.sub(str, 7, 12) + return 3600 * hr + 60 * mn + sc +end + +local function buildFileTree() + if not fileTree then + guiPause.title = "READING..." + gui = guiPause + fileTree = { } + fileCount = 0 + getNextFileName = dir("/LOGS") + fileName = getNextFileName() + end + + while fileName do + -- If there are many files, then we may run out of CPU instructions + if getUsage() > 90 then + return + end + + if string.len(fileName) > 23 and string.sub(fileName, -4) == ".csv" then + local dateStr = string.sub(fileName, -21, -12) + local nameStr = string.sub(fileName, -10, -9) .. ":" .. string.sub(fileName, -8, -7) .. ":" .. + string.sub(fileName, -6, -5) .. " " .. string.sub(fileName, 1, -23) + + if not fileTree[dateStr] then + fileTree[dateStr] = { } + fileCount = fileCount + 1 + end + + fileTree[dateStr][nameStr] = fileName + end + + fileName = getNextFileName() + end + + if getUsage() > 20 then + return + end + + getNextFileName = nil + fileName = nil + + if fileCount == 0 then + guiPause.title = "NO LOG FILES" + gui = guiPause + headers = nil + data = { } + else + refreshDates() + gui = guiFile + end + + buildingTree = false +end + +local function readLines(fileName) + -- data[2] = min values, data[3] = max values + data = { { }, { FMAX }, { -FMAX } } + + if not fileName then + return + end + + fileName = "/LOGS/" .. fileName + local fileStat = fstat(fileName) + + if not fileStat then + return + end + + local l = string.len(DEFAULT_PLOT) + local plotIdx = 2 + local logFile = io.open(fileName, "r") + local logString = io.read(logFile, fileStat.size) + io.close(logFile) + lines = { } + + local i = 0 + for line in string.gmatch(logString, "[^\n]+") do + i = i + 1 + lines[i] = line + end + + if #lines < 3 then + return + end + + local headers = { } + i = -1 + for field in string.gmatch(lines[1], "[^,]+") do + i = i + 1 + if i >= 1 then + headers[i] = field + end + end + + for i = 2, #headers do + if string.sub(headers[i], 1, l) == DEFAULT_PLOT then + plotIdx = i + end + if headers[i] == FIRST_EXCLUDED then + break + end + data[1][i - 1] = headers[i] + data[2][i] = FMAX + data[3][i] = -FMAX + end + + local ddp = guiGraph.ddPlot + if #data[1] == 0 then + ddp.disabled = true + else + ddp.disabled = false + ddp.items = data[1] + if ddp.selected > #data[1] then + ddp.selected = plotIdx - 1 + end + end + gui = guiGraph +end + +local function readData() + local plotIdxLast = #data[1] + 1 + + for i = #data - 1, #lines do + if getUsage() > 90 then + return + end + local j = -1 + local y + local record = { } + for field in string.gmatch(lines[i], "[^,]+") do + j = j + 1 + if j > 0 then + if j > plotIdxLast then + break + elseif j > 1 then + y = tonumber(field) + else + y = timeSerial(field) + end + record[j] = y + data[2][j] = math.min(y, data[2][j]) + data[3][j] = math.max(y, data[3][j]) + end + end + data[i + 2] = record + end + lines = nil + cursor = math.ceil((#data + 3) / 2) +end + +local function readSelected() + local date = menu1.items[menu1.selected] + local name = menu2.items[menu2.selected] + guiGraph.title = name + fileName = fileTree[date][name] + readLines(fileName) +end + +-------------------------------- Setup GUI -------------------------------- + +-- Common GUI setup +local function setupGUI(title) + local gui = libGUI.newGUI() + gui.title = title + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, gui.title, bit32.bor(DBLSIZE, colors.primary2)) + + -- Extra drawing + gui.drawMore() + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + return gui +end + +-- GUI to show if there are no log files +guiPause = setupGUI("Graph") +guiPause.title = "" + +function guiPause.drawMore() + lcd.drawText(LCD_W / 2, LCD_H / 2, guiPause.title, XXLSIZE + CENTER + VCENTER + colors.primary1) +end + +-- GUI for selecting log file +do + guiFile = setupGUI("Select a log file") + + function guiFile.drawMore() + lcd.drawLine(COL2 - LFT / 2, TOP, COL2 - LFT / 2, BOTTOM, SOLID, colors.primary1) + end + + local function refreshTimes() + local date = menu1.items[menu1.selected] + local times + if fileTree[date] then + times = { } + for t in pairs(fileTree[date]) do + times[#times + 1] = t + end + table.sort(times) + else + times = { "No files" } + end + menu2.items = times + menu2.selected = 1 + end + + function refreshDates() + local dates = { } + for d in pairs(fileTree) do + dates[#dates + 1] = d + end + table.sort(dates) + menu1.items = dates + refreshTimes() + end + + local function onMenu1() + refreshTimes() + guiFile.onEvent(EVT_VIRTUAL_NEXT) + guiFile.onEvent(EVT_VIRTUAL_ENTER) + end + + menu1 = guiFile.menu(LFT, TOP, W1, BOTTOM - TOP, nil, onMenu1) + + local function onMenu2() + readSelected() + guiFile.onEvent(EVT_VIRTUAL_PREV) + guiFile.onEvent(EVT_VIRTUAL_ENTER) + end + + menu2 = guiFile.menu(COL2, TOP, W2, BOTTOM - TOP, nil, onMenu2) -- Add graph function + + guiFile.onEvent(EVT_VIRTUAL_NEXT) + guiFile.onEvent(EVT_VIRTUAL_ENTER) +end -- Setup guiFile + +-- GUI for plotting the graph +do + guiGraph = setupGUI("") + local toggleCursor + + local y = TOP + guiGraph.ddPlot = guiGraph.dropDown(BUTTON_X, y, BUTTON_W, HEIGHT, { "1", "2", "3", "4", "5", "6", "- - -" }, 7, nil, CENTER) + + y = y + LINE + guiGraph.button(BUTTON_X, y, BUTTON_W, HEIGHT, "New file", function() gui = guiFile end) + + y = y + LINE + + local function moveCursor(d) + cursor = cursor + d + if cursor > #data then + cursor = 4 + elseif cursor < 4 then + cursor = #data + end + end + + -- Trap events with prompt when cursor is active + local trapCursor = { + run = function(event, touchState) + if touchState then + local tx, ty = touchState.x - LFT, touchState.y + if 0 <= tx and tx <= PLOT_W and TOP <= ty and ty <= TOP + PLOT_H then + local x = tx / xScale + xMin + local y = (y0 - ty) / yScale + -- Find the nearest x-values + local i1 = 4 + local i2 = #data + while i2 - i1 > 1 do + local i = math.floor((i1 + i2) / 2) + if data[i][1] <= x then + i1 = i + else + i2 = i + end + end + -- Search for nearest point within x-window + local ddMin = FMAX + local plotIdx = guiGraph.ddPlot.selected + 1 + for i = math.max(4, i1 - 4), math.min(#data, i2 + 4) do + x = LFT + xScale * (data[i][1] - xMin) + y = y0 - yScale * data[i][plotIdx] + local dd = (tx - x) ^ 2 + (ty - y) ^ 2 + if dd < ddMin then + ddMin = dd + cursor = i + end + end + elseif event == EVT_TOUCH_TAP then + toggleCursor.onEvent(EVT_VIRTUAL_ENTER) + end + elseif event == EVT_VIRTUAL_ENTER then + toggleCursor.onEvent(event) + elseif event == EVT_VIRTUAL_PREV then + moveCursor(-1) + elseif event == EVT_VIRTUAL_NEXT then + moveCursor(1) + end + end + } + + local function onToggleCursor() + if toggleCursor.value then + guiGraph.showPrompt(trapCursor) + else + guiGraph.dismissPrompt() + end + end + + toggleCursor = guiGraph.toggleButton(BUTTON_X, y, BUTTON_W, HEIGHT, "Cursor", false, onToggleCursor) + + local function onArrows(d) + local s = menu2.selected + d + if s < 1 then + s = #menu2.items + elseif s > #menu2.items then + s = 1 + end + menu2.selected = s + readSelected() + end + + y = BOTTOM - HEIGHT + local w = (BUTTON_W - MARGIN) / 2 + guiGraph.button(BUTTON_X, y, w, HEIGHT, CHAR_LEFT, function() onArrows(-1) end) + guiGraph.button(BUTTON_X + MARGIN + w, y, w, HEIGHT, CHAR_RIGHT, function() onArrows(1) end) + + function guiGraph.drawMore() + local plotIdx = guiGraph.ddPlot.selected + 1 + + -- Background + lcd.drawFilledRectangle(LFT, TOP, PLOT_W, PLOT_H, colors.primary2) + lcd.drawRectangle(LFT, TOP, PLOT_W, PLOT_H, COLOR_THEME_SECONDARY2) + + if lines then + local txt = "READING DATA" + local flags = DBLSIZE + CENTER + VCENTER + colors.primary1 + lcd.drawText(LFT + PLOT_W / 2, TOP + PLOT_H / 2, txt, DBLSIZE + CENTER + VCENTER + colors.primary1) + readData() + return + elseif #data < 6 or #data[1] == 0 then + local txt = "NO DATA IN THIS FILE" + local flags = DBLSIZE + VCENTER + CENTER + colors.primary1 + lcd.drawText(LFT + PLOT_W / 2, TOP + PLOT_H / 2, txt, flags) + return + end + + -- Time scale + xMin = data[2][1] + local xRange = math.max(60, data[3][1] - xMin) + xScale = PLOT_W / xRange + -- Y-scale + local yRange = data[3][plotIdx] - data[2][plotIdx] + local mag = math.max(-2, math.floor(math.log(yRange, 10))) + local yTick + local r = yRange / 10^mag + if r > 6 then + yTick = 2 * 10^mag + elseif r > 3 then + yTick = 1 * 10^mag + elseif r > 2.4 then + yTick = 0.5 * 10^mag + elseif r > 1.2 then + yTick = 0.4 * 10^mag + else + yTick = 0.2 * 10^mag + end + yTick = math.max(0.01, yTick) + local yMin = yTick * math.floor(data[2][plotIdx] / yTick) + local yMax = yTick * math.ceil(data[3][plotIdx] / yTick) + if yMin == yMax then + yMin = yMin - yTick + yMax = yMax + yTick + end + yScale = PLOT_H / (yMax - yMin) + y0 = BOTTOM + yScale * yMin + -- Flags for number precision + local fmt + if yTick < 0.1 then + fmt = "%1.2f" + elseif yTick < 1 then + fmt = "%2.1f" + else + fmt = "%3i" + end + -- Lines + for x = 0, xRange, 60 do + local xx = LFT + xScale * x + lcd.drawLine(xx, TOP, xx, BOTTOM, DOTTED, COLOR_THEME_SECONDARY2) + if x > 0 then + lcd.drawNumber(xx, BOTTOM, x / 60, CENTER + colors.primary3) + end + end + for y = yMin, yMax, yTick do + local yy = y0 - yScale * y + if math.abs(y) < 1E-12 then + lcd.drawLine(LFT, yy, RGT, yy, SOLID, COLOR_THEME_SECONDARY2) + else + lcd.drawLine(LFT, yy, RGT, yy, DOTTED, COLOR_THEME_SECONDARY2) + end + lcd.drawText(LFT, yy, string.format(fmt, y), VCENTER + RIGHT + colors.primary3) + end + -- Graph curve + local x1 = LFT + xScale * (data[4][1] - xMin) + local y1 = y0 - yScale * data[4][plotIdx] + for i = 5, #data do + local x2 = LFT + xScale * (data[i][1] - xMin) + local y2 = y0 - yScale * data[i][plotIdx] + lcd.drawLine(x1, y1, x2, y2, SOLID, COLOR_THEME_SECONDARY1, 3) + x1, y1 = x2, y2 + end + -- Cursor point + if toggleCursor.value then + local delta + local flags = CENTER + COLOR_THEME_SECONDARY1 + x1 = LFT + xScale * (data[cursor][1] - xMin) + y1 = y0 - yScale * data[cursor][plotIdx] + lcd.drawFilledCircle(x1, y1, 5, colors.active) + lcd.drawCircle(x1, y1, 4, COLOR_THEME_SECONDARY1) + lcd.drawCircle(x1, y1, 5, COLOR_THEME_SECONDARY1) + -- Slope + if cursor == 4 then + delta = (data[cursor + 1][plotIdx] - data[cursor][plotIdx]) / (data[cursor + 1][1] - data[cursor][1]) + elseif cursor == #data then + delta = (data[cursor][plotIdx] - data[cursor - 1][plotIdx]) / (data[cursor][1] - data[cursor - 1][1]) + else + delta = (data[cursor + 1][plotIdx] - data[cursor - 1][plotIdx]) / (data[cursor + 1][1] - data[cursor - 1][1]) + end + -- Plot value and slope + if y1 - TOP < 24 then + y1 = y1 + 8 + elseif BOTTOM - y1 < 24 then + y1 = y1 - 56 + else + y1 = y1 - 24 + end + lcd.drawText(x1, y1, string.format("Y=" .. fmt, data[cursor][plotIdx]), flags) + lcd.drawText(x1, y1 + 24, string.format(CHAR_DELTA .. "=" .. fmt, 60 * delta), flags) + end + end + + guiGraph.onEvent(EVT_VIRTUAL_NEXT) +end -- Setup guiGraph + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + buildingTree = true + fileTree = nil +end -- background() + +function widget.refresh(event, touchState) + if not event then + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + widget.background() + return + end + + if buildingTree then + buildFileTree() + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/mixes.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/mixes.lua new file mode 100644 index 00000000..6a89fe76 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/mixes.lua @@ -0,0 +1,214 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K configure mixes and battery warning, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui = libGUI.newGUI() +local colors = libGUI.colors +local title = "Mixes & Battery" +local modelType = "" +local fm = getFlightMode() + +-- Screen drawing constants +local LCD_W2 = LCD_W / 2 +local HEADER = 40 +local LINE = 32 +local HEIGHT = LINE - 4 +local MARGIN = 15 +local W1 = 170 +local W2 = LCD_W2 - 2 * MARGIN - W1 + +local mixes_F3K = { + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, -100, 100}, + {"Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Elevator input", 6, 20, 100}, + {"Aileron input", 7, 20, 100}, + {"Exponential", 8, 20, 100} +} + +local mixes_F3K_RE = { + {"Elevator input", 6, 20, 100}, + {"Exponential", 8, 20, 100} +} + +local mixes_F3K_FH = { + {"Elevator input", 7, 20, 100}, + {"Aileron input", 0, 10, 100}, + {"Aileron " .. CHAR_RIGHT .. " flaps", 1, 0, 100}, + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, 0, 100}, + {"Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Camber " .. CHAR_RIGHT .. " aileron", 6, 0, 200}, + {"Exponential", 8, 0, 100} +} + +local mixes_FxJ = { + {"Aileron " .. CHAR_RIGHT .. " Rudder", 2, -100, 100}, + {"Aileron Travel", 0, -100, 100}, + {"Aileron " .. CHAR_RIGHT .. " Flap", 1, -100, 100}, + {"Aileron Differential", 3, -100, 100}, + {"Brake " .. CHAR_RIGHT .. " Elevator", 4, 0, 40}, + {"Snap - flap", 5, 0, 50}, + {"Camber " .. CHAR_RIGHT .." Aileron", 6, 0, 400} +} + +local mixes_FXY = { + {"Aileron " .. CHAR_RIGHT .. " rudder", 2, -100, 100} +} + +local mixes = mixes_F3K + +-------------------------------- Setup GUI -------------------------------- + +do + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_TRAD" then + mixes = mixes_F3K + elseif modelType == "F3K_FH" then + mixes = mixes_F3K_FH + elseif modelType == "F3K_RE" then + mixes = mixes_F3K_RE + elseif modelType == "F3J" or modelType == "F5J" then + mixes = mixes_FxJ + else + mixes = mixes_FXY + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Fligh mode + local fmIdx, fmStr = getFlightMode() + lcd.drawText(LCD_W - HEADER, HEADER / 2, "FM" .. fmIdx .. ":" .. fmStr, RIGHT + VCENTER + MIDSIZE + colors.primary2) + + -- Line stripes + for i = 1, 3, 2 do + lcd.drawFilledRectangle(0, HEADER + LINE * i, LCD_W, LINE, COLOR_THEME_SECONDARY2) + end + + local bottom = HEADER + 4 * LINE + lcd.drawLine(LCD_W2, HEADER, LCD_W2, bottom, SOLID, colors.primary1) + + -- Help text + local txt = "Some variables can be adjusted individually for each flight mode.\n" .. + "Therefore, select the flight mode for which you want to adjust.\n" .. + "You can change that behaviour under GLOBAL VARIABLES." + lcd.drawTextLines(MARGIN, bottom + 25, LCD_W - 2 * MARGIN, LCD_H - bottom, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Grid for items + local x, y = MARGIN, HEADER + 2 + + local function move() + if x == MARGIN then + x = x + LCD_W2 + else + x = MARGIN + y = y + LINE + end + end + + -- Add label and number element for a GV + local function addGV(label, gv, min, max) + gui.label(x, y, W1, HEIGHT, label) + + local function changeGV(delta, number) + local value = number.value + delta + value = math.max(value, min) + value = math.min(value, max) + model.setGlobalVariable(gv, fm, value) + return value + end + + local number = gui.number(x + W1, y, W2, HEIGHT, 0, changeGV, RIGHT + libGUI.flags) + + function number.update() + number.value = model.getGlobalVariable(gv, fm) + end + + move() + end + + -- ADD GVs + for i, mix in ipairs(mixes) do + addGV(mix[1], mix[2], mix[3], mix[4]) + end + + -- Add battery warning + gui.label(x, y, W1, HEIGHT, "Battery warning level (V)") + + local function changeBattery(delta, bat) + local value = bat.value + delta + value = math.max(0, value) + value = math.min(200, value) + soarGlobals.setParameter(soarGlobals.batteryParameter, value - 100) + return value + end + + local batP = soarGlobals.getParameter(soarGlobals.batteryParameter) + gui.number(x + W1, y, W2, HEIGHT, batP + 100, changeBattery, RIGHT + PREC1 + libGUI.flags) +end -- Setup GUI + +function widget.background() +end -- background() + +function widget.refresh(event, touchState) + if not event then + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + end + + fm = getFlightMode() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/name.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/name.lua new file mode 100644 index 00000000..d8c77c6c --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/name.lua @@ -0,0 +1,38 @@ +--------------------------------------------------------------------------- +-- SoarETX model name, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-08 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget = ... +local name = model.getInfo().name +local att = SMLSIZE + +for i, a in ipairs({ DBLSIZE, MIDSIZE, BOLD, 0 }) do + local w = lcd.sizeText(name, a) + if w <= widget.zone.w then + att = a + break + end +end + +att = att + VCENTER + COLOR_THEME_PRIMARY2 + +function widget.refresh(event, touchState) + lcd.drawText(0, widget.zone.h / 2, name, att) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/outputs.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/outputs.lua new file mode 100644 index 00000000..a0738913 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/outputs.lua @@ -0,0 +1,595 @@ +--------------------------------------------------------------------------- +-- SoarETX outputs configuration widget, loadable part -- +-- -- +-- Author: Jesper Frickmann -- +-- Date: 2022-02-19 -- +-- Version: 1.0.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui +local colors = libGUI.colors +local title = "Outputs" + +local warningPrompt = libGUI.newGUI() -- Warning prompt shown on opening +local editPrompt = libGUI.newGUI() -- Prompt asking what to edit +local channels -- List sub-GUIs for named channels +local focusNamed = 0 -- Index of sub-GUI in focus +local firstLine = 1 -- Index of sub-GUI on the first line +local editPoints = 0 -- Select what points to edit + +local N = 32 -- Highest channel number to swap +local MAXOUT = 1500 -- Maximum output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local CHAN_BASE = getFieldInfo("ch1").id - 1 -- Base of channel sources + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 10 +local TOP = 50 +local ROW = 38 +local CTR = 340 +local STEP = 10 +local SCALE = 12 +local MAXOUT = 1500 +local MINDIF = 100 + +-- Function that gives the active points for a given value of editPoints +local function activePoints(ep) + local p = { 0, 0, 0 } + if ep == 1 then + p[1] = 1 + p[2] = 1 + p[3] = 1 + elseif ep == 2 then + p[1] = -1 + p[3] = 1 + elseif ep == 3 then + p[1] = 1 + elseif ep == 4 then + p[2] = 1 + else -- 5 + p[3] = 1 + end + return p +end -- activePoints(...) + +-- Setup warning prompt +do + local PROMPT_W = 300 + local PROMPT_H = 172 + warningPrompt.x = (LCD_W - PROMPT_W) / 2 + warningPrompt.y = (LCD_H - PROMPT_H) / 2 + + function warningPrompt.fullScreenRefresh() + local txt = "Please disable the motor!\n\n" .. + "Sudden spikes may occur when channels are moved.\n\n" .. + "Press ENTER to proceed." + + warningPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) + warningPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) + warningPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) + warningPrompt.drawText(MARGIN, HEADER / 2, "W A R N I N G", DBLSIZE + VCENTER + libGUI.colors.primary2) + warningPrompt.drawTextLines(MARGIN, HEADER + MARGIN, PROMPT_W - 2 * MARGIN, PROMPT_H - 2 * MARGIN, txt) + end + + -- Make a dismiss button from a custom element + local custom = warningPrompt.custom({ }, PROMPT_W - 30, 10, 20, 20) + + function custom.draw(focused) + warningPrompt.drawRectangle(PROMPT_W - 30, 10, 20, 20, libGUI.colors.primary2) + warningPrompt.drawText(PROMPT_W - 20, 20, "X", MIDSIZE + CENTER + VCENTER + libGUI.colors.primary2) + if focused then + custom.drawFocus() + end + end + + function custom.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + gui.dismissPrompt() + end + end +end -- Warning prompt + +-- Setup prompt for selecting what to edit +do + local PROMPT_W = 280 + local PROMPT_H = 210 + local MENU_W = 75 + local MENU_H = PROMPT_H - HEADER - 2 * MARGIN + local X = { 110, 180, 250 } + local MAX_D = 20 + local t0 = 0 + local h = select(2, lcd.sizeText("", libGUI.flags)) + local menuItems = { + "Offset", + "Range", + "Lower", + "Center", + "Upper" + } + editPrompt.x = (LCD_W - PROMPT_W) / 2 + editPrompt.y = (LCD_H - PROMPT_H) / 2 + + function editPrompt.fullScreenRefresh() + if not editPrompt.editing then + editPoints = 0 + gui.dismissPrompt() + gui.onEvent(EVT_VIRTUAL_EXIT) + return + end + + editPrompt.drawFilledRectangle(0, 0, PROMPT_W, HEADER, COLOR_THEME_SECONDARY1) + editPrompt.drawFilledRectangle(0, HEADER, PROMPT_W, PROMPT_H - HEADER, libGUI.colors.primary2) + editPrompt.drawRectangle(0, 0, PROMPT_W, PROMPT_H, libGUI.colors.primary1, 2) + editPrompt.drawText(MARGIN, HEADER / 2, "Select what to edit:", DBLSIZE + VCENTER + libGUI.colors.primary2) + + local y = HEADER + MARGIN + h / 2 + + for i = 1, 5 do + local p = activePoints(i) + editPrompt.drawFilledRectangle(X[1], y - 2, X[3] - X[1], 5, libGUI.colors.primary1) + for j = 1, 3 do + if p[j] == 0 then + editPrompt.drawFilledRectangle(X[j] - 2, y - 10, 5, 20, libGUI.colors.primary1) + else + editPrompt.drawFilledCircle(X[j], y, 10, libGUI.colors.edit) + for i = -1, 1 do + editPrompt.drawCircle(X[j], y, 10 + i, libGUI.colors.active) + end + end + end + y = y + h + end + end -- fullScreenRefresh() + + local function onMenu(menu) + editPoints = menu.selected + gui.dismissPrompt() + end -- onMenu(...) + + editPrompt.menu(MARGIN, HEADER + MARGIN, MENU_W, MENU_H, menuItems, onMenu) +end -- Prompt for selecting what to edit + +-- Move output channel by swapping with previous or next; direction = -1 or +1 +local function MoveOutput(direction, channel) + local m = { } -- Channel indices + m[1] = channel.iChannel -- Channel to move + m[2] = m[1] + direction -- Neighbouring channel to swap + + -- Are we at then end? + if m[2] < 1 or m[2] > N then + playTone(3000, 100, 0, PLAY_NOW) + return + end + + local outputs = { } -- List of output tables + local mixes = { } -- List of lists of mixer tables + + -- Read channel into tables + for i = 1, 2 do + outputs[i] = model.getOutput(m[i] - 1) + + -- Read list of mixer lines + mixes[i] = { } + for j = 1, model.getMixesCount(m[i] - 1) do + mixes[i][j] = model.getMix(m[i] - 1, j - 1) + end + end + + -- Write back swapped data + for i = 1, 2 do + model.setOutput(m[i] - 1, outputs[3 - i]) + + -- Delete existing mixer lines + for j = 1, model.getMixesCount(m[i] - 1) do + model.deleteMix(m[i] - 1, 0) + end + + -- Write back mixer lines + for j, mix in pairs(mixes[3 - i]) do + model.insertMix(m[i] - 1, j - 1, mix) + end + end + + -- Swap sources for the two channels in all mixes + for i = 1, N do + local mixes = { } -- List of mixer tables + local dirty = false -- If any sources were swapped, then write back data + + -- Read mixer lines and swap sources if they match the two channels being swapped + for j = 1, model.getMixesCount(i - 1) do + mixes[j] = model.getMix(i - 1, j - 1) + if mixes[j].source == m[1] + CHAN_BASE then + dirty = true + mixes[j].source = m[2] + CHAN_BASE + elseif mixes[j].source == m[2] + CHAN_BASE then + dirty = true + mixes[j].source = m[1] + CHAN_BASE + end + end + + -- Do we have to write back data? + if dirty then + -- Delete existing mixer lines + for j = 1, model.getMixesCount(i - 1) do + model.deleteMix(i - 1, 0) + end + + -- Write new mixer lines + for j, mix in ipairs(mixes) do + model.insertMix(i - 1, j - 1, mix) + end + end + end + + -- Update channel GUI(s) on the screen + channel.iChannel = m[2] + channel.output = outputs[1] + local iNamed2 = channel.iNamed + direction + local channel2 = channels[iNamed2] + if channel2 and channel2.iChannel == m[2] then + -- Swapping two named channels! + channel2.iChannel = m[1] + channel2.output = outputs[2] + channels[channel.iNamed], channels[iNamed2] = channel2, channel + channel.iNamed, channel2.iNamed = iNamed2, channel.iNamed + gui.moveFocused(direction) + end +end -- MoveOutput() + +local function init() + -- Start building GUI from scratch + gui = libGUI.newGUI() + gui.showPrompt(warningPrompt) + + function gui.fullScreenRefresh() + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(MARGIN, HEADER / 2 - 2, "Configure Outputs", DBLSIZE + VCENTER + colors.primary2) + + -- Row background + for i = 0, 6 do + local y = HEADER + i * ROW + if i % 2 == 1 then + lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY2) + else + lcd.drawFilledRectangle(0, y, LCD_W, ROW, COLOR_THEME_SECONDARY3) + end + end + + -- Adjust scroll for channels + if focusNamed > 0 then + if focusNamed < firstLine then + firstLine = focusNamed + elseif firstLine + 5 < focusNamed then + firstLine = focusNamed - 5 + end + end + focusNamed = 0 + + -- Draw vertical reference lines + for i = -6, 6 do + local x = CTR - i * MAXOUT / (SCALE * 6) + 2 + lcd.drawLine(x, HEADER, x, HEADER + 6 * ROW, DOTTED, FORCE, COLOR_THEME_DISABLED) + end + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Build the list of named channels, each in their own movable GUI + do + local HEIGHT = ROW - 8 + local iNamed = 0 + channels = { } + + for iChannel = 1, N do + local output = model.getOutput(iChannel - 1) + + if output and output.name ~= "" then + local channel = gui.gui(2, LCD_H, LCD_W - 4, ROW - 4) + local d0 + + iNamed = iNamed + 1 + channels[iNamed] = channel + channel.iNamed = iNamed + channel.iChannel = iChannel + channel.output = output + + -- Hack the sub-GUI's draw function to do a few extra things + local draw = channel.draw + function channel.draw(focused) + -- Needed to adjust scroll in fullScreenRefresh() + if focused then + focusNamed = channel.iNamed + end + -- If channel is not visible, place it outside the screen to avoid receiving touch events + if channel.iNamed < firstLine or channel.iNamed > firstLine + 5 then + channel.y = LCD_H + else + channel.y = HEADER + (channel.iNamed - firstLine) * ROW + 2 + draw(focused) + end + end + + -- Hack the sub-GUI's onEvent function to do finger scrolling + local onEvent = channel.onEvent + function channel.onEvent(event, touchState) + if event == EVT_TOUCH_SLIDE and not channel.editing then + firstLine = math.floor(channel.iNamed - (touchState.y - HEADER - ROW / 2) / ROW + 0.5) + firstLine = math.min(firstLine, #channels - 5, channel.iNamed) + firstLine = math.max(firstLine, 1, channel.iNamed - 5) + else + onEvent(event, touchState) + end + end -- onEvent(...) + + -- Custom element for changing output channel (and moving all mixer lines etc.) + local nbrChannel = channel.custom({ }, 2, 2, 30, HEIGHT) + + function nbrChannel.draw(focused) + local fg = libGUI.colors.primary1 + if focused then + nbrChannel.drawFocus() + if channel.editing then + fg = libGUI.colors.primary2 + channel.drawFilledRectangle(2, 2, 30, HEIGHT, libGUI.colors.edit) + end + end + channel.drawNumber(30, HEIGHT / 2 + 2, channel.iChannel, libGUI.flags + VCENTER + RIGHT + fg) + end + + function nbrChannel.onEvent(event, touchState) + if channel.editing then + if libGUI.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + channel.editing = false + elseif event == EVT_VIRTUAL_INC then + MoveOutput(1, channel) + elseif event == EVT_VIRTUAL_DEC then + MoveOutput(-1, channel) + elseif event == EVT_TOUCH_FIRST then + d0 = 0 + elseif event == EVT_TOUCH_SLIDE then + local d = math.floor((touchState.y - touchState.startY) / ROW + 0.5) + if d ~= d0 then + MoveOutput(d - d0, channel) + d0 = d + end + end + elseif event == EVT_VIRTUAL_ENTER then + channel.editing = true + end + end -- onEvent(...) + + -- Label for channel name + local lblName = channel.label(32, 2, 140, HEIGHT, ". " .. channel.output.name) + + -- Custom element to invert output direction + local revert = channel.custom({ }, 172, 2, 30, HEIGHT) + + function revert.draw(focused) + local y = HEIGHT / 2 + 3 + if channel.output.revert == 1 then + channel.drawFilledRectangle(178, y - 1, 19, 3, colors.primary1) + for x = 177, 180 do + channel.drawLine(x, y, x + 8, y - 8, SOLID, colors.primary1) + channel.drawLine(x, y, x + 8, y + 8, SOLID, colors.primary1) + end + else + channel.drawFilledRectangle(177, y - 1, 19, 3, colors.primary1) + for x = 194, 197 do + channel.drawLine(x, y, x - 8, y - 8, SOLID, colors.primary1) + channel.drawLine(x, y, x - 8, y + 8, SOLID, colors.primary1) + end + end + + function revert.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER then + channel.output.revert = 1 - channel.output.revert + model.setOutput(channel.iChannel - 1, channel.output) + end + end + + if focused then + revert.drawFocus() + end + end + + -- Custom element to adjust center and end points + do + local interval = channel.custom({ }, 210, 2, 264, HEIGHT) + interval.editable = true + local flags = SMLSIZE + CENTER + INVERS + libGUI.colors.primary2 + local x + local y = HEIGHT / 2 + 2 + local yLbl = y - 12 - select(2, lcd.sizeText("", flags)) + local iScroll = 0 + + function interval.draw(focused) + local output = channel.output + local p = { 0, 0, 0 } + local colorBar = libGUI.colors.primary3 + local colorDot = libGUI.colors.primary2 + local colorDotBorder = libGUI.colors.primary3 + + x = { + CTR + output.min / SCALE, + CTR + output.offset / SCALE, + CTR + output.max / SCALE + } + if focused then + colorDotBorder = libGUI.colors.active + if channel.editing then + -- Draw value labels + channel.drawNumber(x[1], yLbl, 0.1 * output.min, flags) + channel.drawNumber(x[2], yLbl, 0.1 * output.offset, flags) + channel.drawNumber(x[3], yLbl, 0.1 * output.max, flags) + colorBar = libGUI.colors.primary1 + colorDot = libGUI.colors.edit + p = activePoints(editPoints) + else + interval.drawFocus() + end + end + -- Draw figure + channel.drawFilledRectangle(x[1], y - 2, x[3] - x[1], 5, colorBar) + for j = 1, 3 do + if p[j] == 0 then + channel.drawFilledRectangle(x[j] - 1, y - 10, 3, 20, colorBar) + else + channel.drawFilledCircle(x[j], y, 10, colorDot) + for i = -1, 1 do + channel.drawCircle(x[j], y, 10 + i, colorDotBorder) + end + end + end + -- Draw position indicators + local outX = getValue(CHAN_BASE + channel.iChannel) + if outX >= 0 then + outX = output.offset + math.min(outX, 1024) * (output.max - output.offset) / 1024 + else + outX = output.offset + math.max(outX, -1024) * (output.offset - output.min) / 1024 + end + outX = CTR + outX / SCALE + channel.drawFilledTriangle(outX, y - 3, outX - 3, y - 9, outX + 3, y - 9, colorBar) + channel.drawLine(outX, y - 2, outX, y + 2, SOLID, colorBar) + channel.drawFilledTriangle(outX, y + 3, outX - 3, y + 9, outX + 3, y + 9, colorBar) + end -- draw(...) + + local RR = 14 ^ 2 + + local function ptCovers(p, q) + local ap = activePoints(editPoints) + + for i = 1, 3 do + if ap[i] ~= 0 and (x[i] - p) ^ 2 + (y - q) ^ 2 <= RR then + return i + end + end + return 0 + end -- ptCovers(...) + + local function adjustPoints(d) + local output = channel.output + local p = activePoints(editPoints) + local min = output.min + local ctr = output.offset + local max = output.max + + -- Check limits + if p[1] == -1 then + d = math.min(d, math.max(0, MAXOUT + min)) + elseif p[1] == 1 then + d = math.max(d, math.min(0, -(MAXOUT + min))) + end + + if p[2] - p[1] == 1 then + d = math.max(d, math.min(0, MINDIF + min - ctr)) + elseif p[2] - p[1] == -1 then + d = math.min(d, math.max(0, ctr - min - MINDIF)) + end + + if p[3] - p[2] == 1 then + d = math.max(d, math.min(0, MINDIF + ctr - max)) + elseif p[3] - p[2] == -1 then + d = math.min(d, math.max(0, max - ctr - MINDIF)) + end + + if p[3] == 1 then + d = math.min(d, math.max(0, MAXOUT - max)) + end + + -- Update output values + output.min = min + p[1] * d + output.offset = ctr + p[2] * d + output.max = max + p[3] * d + + -- Write back data + model.setOutput(channel.iChannel - 1, output) + end + + function interval.onEvent(event, touchState) + if event == EVT_VIRTUAL_ENTER and not channel.editing then + channel.editing = true + editPrompt.onEvent(EVT_VIRTUAL_ENTER) + channel.showPrompt(editPrompt) + return + end + + if event == EVT_TOUCH_SLIDE and iScroll > 0 then + local p = activePoints(editPoints)[iScroll] + local d = STEP * math.floor(p * (touchState.x - x[iScroll]) * SCALE / STEP + 0.5) + adjustPoints(d) + else + iScroll = 0 + end + + if event == EVT_TOUCH_FIRST then + iScroll = ptCovers(touchState.x, touchState.y) + if iScroll > 0 then + x0 = x[iScroll] + end + elseif libGUI.match(event, EVT_VIRTUAL_ENTER, EVT_VIRTUAL_EXIT) then + editPoints = 0 + channel.editing = false + elseif event == EVT_VIRTUAL_INC then + adjustPoints(STEP) + elseif event == EVT_VIRTUAL_DEC then + adjustPoints(-STEP) + end + end -- onEvent(...) + end -- Setup interval + end + end + end +end -- init() + +function widget.refresh(event, touchState) + if not event then + gui = nil + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + init() + return + end + + gui.run(event, touchState) +end -- refresh(...) + +function widget.background() + gui = nil +end -- background() diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/switch.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/switch.lua new file mode 100644 index 00000000..eeeb44c2 --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/switch.lua @@ -0,0 +1,215 @@ +--------------------------------------------------------------------------- +-- SoarETX F3K switch setup, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = 0 +local gui +local colors = libGUI.colors +local title = "Switches" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local MARGIN = 25 +local LINE = 29 +local HEIGHT = 25 +local WIDTH = 60 +local COL2 = LCD_W - MARGIN - WIDTH + +-- List of 1. Text label 2. logical switch +local items_F3K = { -- For R3K + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, + { "Data logging (when flight timer is running)", 7 } +} + +local items_F3K_RE = { -- For R3K_RE + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Report remaining window time every 10 sec.", 4 }, + { "Report current altitude every 10 sec.", 5 }, + { "Launch mode and flight timer control", 6 }, + { "Data logging (when flight timer is running)", 7 } +} + +local items_F5K = { + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Motor ARM ON/OFF", 4}, + { "Report remaining window time every 10 sec.", 5 }, + { "Report current altitude every 10 sec.", 6 }, + { "Launch mode and flight timer control", 7 }, + { "Data logging (when flight timer is running)", 8 } +} + +local items_FxJ = { + { "Allow vario and voice reporting of altitude", 0 }, + { "Variometer sound", 1 }, + { "Speed flight mode", 2 }, + { "Float flight mode", 3 }, + { "Report remaining window time every 10 sec.", 6 }, + { "Report current altitude every 10 sec.", 7 }, + { "Launch mode (Motor Arm) and flight timer control", 4 }, + { "Start/Stop timer and Motor", 8 }, + { "Data logging (when flight timer is running)", 9 } +} + +local items_FXY = { + { "Allow vario and voice reporting of altitude", 0 } +} + +local items = items_FXY + +-------------------------------- Setup GUI -------------------------------- + +local function init() + gui = libGUI.newGUI() + + function gui.fullScreenRefresh() + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Row background + for i = 0, 7 do + local y = HEADER + i * LINE + if i % 2 == 1 then + lcd.drawFilledRectangle(0, y, LCD_W, LINE, COLOR_THEME_SECONDARY2) + else + lcd.drawFilledRectangle(0, y, LCD_W, LINE, COLOR_THEME_SECONDARY3) + end + end + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Build the list of drop downs + local y = HEADER + 2 + local w1 = COL2 - MARGIN + + -- Build lists of physical switch position indices and names + local swIndices = { } + local swNames = { } + local MAX_SW = getSwitchIndex(CHAR_TRIM .. "Rl") - 1 + for swIdx, swName in switches(-MAX_SW, MAX_SW) do + if swIdx ~= 0 then + i = #swIndices + 1 + swIndices[i] = swIdx + swNames[i] = swName + end + end + + local function setSwitch(dropDown) + lsTbl = model.getLogicalSwitch(dropDown.ls) + swIdx = swIndices[dropDown.selected] + lsTbl.v1 = swIdx + model.setLogicalSwitch(dropDown.ls, lsTbl) + end + + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_FH" or modelType == "F3K_TRAD" then + items = items_F3K + elseif modelType == "F3K_RE" then + items = items_F3K_RE + elseif modelType == "F5K" then + items = items_F5K -- Make it smaller to fit extra line + HEIGHT = 20 + LINE = 25 + elseif modelType == "F3J" or modelType == "F5J" then + items = items_FxJ + HEIGHT = 20 -- Make it smaller to fit extra line + LINE = 25 + else + items = items_FXY + modelType = "F??" + end + + for i, item in ipairs(items) do + gui.label(MARGIN, y, w1, HEIGHT, item[1]) + + local swIdx = model.getLogicalSwitch(item[2]).v1 + local selected = 0 + + for i, idx in ipairs(swIndices) do + if swIdx == idx then + selected = i + break + end + end + + if selected == 0 then + -- Oops, no switch matching current value in LS! + gui.label(COL2, y, WIDTH, HEIGHT, "???", CENTER + BOLD) + else + local dropDown = gui.dropDown(COL2, y, WIDTH, HEIGHT, swNames, selected, setSwitch, CENTER) + dropDown.ls = item[2] + end + + y = y + LINE + end +end -- init() + +function widget.background() + gui = nil +end -- background() + +function widget.refresh(event, touchState) + if not event then + gui = nil + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + init() + return + end + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/wing2.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/wing2.lua new file mode 100644 index 00000000..ba8234ba --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/wing2.lua @@ -0,0 +1,360 @@ +--------------------------------------------------------------------------- +-- SoarETX flaperon alignment, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui = nil +local colors = libGUI.colors +local title = "Wing alignment" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 40 +local HEIGHT = 150 +local WIDTH = (LCD_W - 3 * DIST_X) / 2 +local TEXT_Y = 210 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 + +-- Other constants +local INP_STEP = getFieldInfo("input7").id -- Step input +local LS_STEP = nil -- Set this LS to apply step input and adjust (model type specific) +local N = 5 -- Number of curve points +local MAX_Y = 1500 -- Max output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels + +-- Flaperon curve indices +local CRV_LFT = 0 +local CRV_RGT = 1 +-- Tables with data for flaperon curves +local lftCrv +local rgtCrv +-- Indices of output channels +local lftOutIdx +local rgtOutIdx +-- Tables with data for flaperon output channels +local lftOut +local rgtOut +-- Tables with y-values after both curve and output settings have been applied +local lftYs = { } +local rgtYs = { } +local activeP -- The point currently being edited + + + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, false) end +end + +local function stepOn() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, true) end +end + + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + gui = nil + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +-- Find the output where the specified curve index is being used +local function GetOutput(crvIndex) + for i = 0, NC - 1 do + local out = model.getOutput(i) + + if out and out.curve == crvIndex then + return i, out + end + end + + stepOff() + gui = nil + error("No output channel with curve CV" .. crvIndex + 1) +end -- GetOutput() + +local function init() + lftCrv = GetCurve(CRV_LFT) + lftOutIdx, lftOut = GetOutput(CRV_LFT) + rgtCrv = GetCurve(CRV_RGT) + rgtOutIdx, rgtOut = GetOutput(CRV_RGT) + stepOn() +end -- init() + +-- Find index of the curve point that corresponds to the value of the step input +local function FindPoint() + local x = getValue(INP_STEP) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) +end -- FindPoint() + +-- Compute output after applying curve and center/endpoints +local function ComputeYs(crv, out, y) + for p = 1, N do + if crv.y[p] < 0 then + y[p] = out.offset + 0.01 * crv.y[p] * (out.offset - out.min) + else + y[p] = out.offset + 0.01 * crv.y[p] * (out.max - out.offset) + end + end +end -- ComputeYs() + +-- Reverse curve points on the left side +local function reverse(ys) + for i = 1, math.floor((N + 1) / 2) do + ys[i], ys[N + 1 - i] = -ys[N + 1 - i], -ys[i] + end +end + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjustment is +/-750 around this offset +local function offset() + local ctr = (N + 1) / 2 + return (activeP - ctr) * 750 / (ctr - 1) +end + +-- Adjust a point, either on a curve or output +local function adjustPoint(crvIdx, crvTbl, outIdx, outTbl, activeP, y) + if activeP == 1 then + outTbl.min = math.min(y, outTbl.offset - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == (N + 1) / 2 then + outTbl.offset = math.min(math.max(y, outTbl.min + MINDIF), outTbl.max - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == N then + outTbl.max = math.max(y, outTbl.offset + MINDIF) + model.setOutput(outIdx, outTbl) + else + crvTbl.y[activeP] = 0.1 * y + model.setCurve(crvIdx, crvTbl) + end +end + +-- Adjust the reversed left curve +local function adjLft(slider) + adjustPoint(CRV_LFT, lftCrv, lftOutIdx, lftOut, N + 1 - activeP, -slider.value - offset()) +end + +-- Adjust the right curve +local function adjRgt(slider) + adjustPoint(CRV_RGT, rgtCrv, rgtOutIdx, rgtOut, activeP, slider.value + offset()) +end + +-- The inverse function of adjust to set slider value from current settings +local function sliderPoint(crvTbl, outTbl, reverse) + local value + local activeP = activeP + + if reverse then + activeP = N + 1 - activeP + end + + if activeP == 1 then + value = outTbl.min + elseif activeP == (N + 1) / 2 then + value = outTbl.offset + elseif activeP == N then + value = outTbl.max + else + value = 10 * crvTbl.y[activeP] + end + + if reverse then + value = -value + end + + return 10 * math.floor(0.1 * (value - offset()) + 0.5) +end + +-- Reset outputs +local function reset() + local midpt = (N + 1) / 2 + + for p = 1, N do + local y = 200.0 / (N - 1) * (p - midpt) + lftCrv.y[p] = y + rgtCrv.y[p] = y + end + model.setCurve(CRV_RGT, rgtCrv) + model.setCurve(CRV_LFT, lftCrv) + + lftOut.min = -1000 + lftOut.offset = 0 + lftOut.max = 1000 + model.setOutput(lftOutIdx, lftOut) + + rgtOut.min = -1000 + rgtOut.offset = 0 + rgtOut.max = 1000 + model.setOutput(rgtOutIdx, rgtOut) + + init() +end -- Reset() + +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + gui = libGUI.newGUI() + + -- Extract Model Type from parametes + modelType = widget.options.Type + + if modelType == "F3K" or modelType == "F3K_TRAD" then + LS_STEP = 10 -- Logical Switch 10 + else + LS_STEP = 10 + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + drawCurve(DIST_X, TOP, WIDTH, HEIGHT, lftYs) + drawCurve(WIDTH + 2 * DIST_X, TOP, WIDTH, HEIGHT, rgtYs) + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen.\n" .. + "First end points, then center, and finally +/-50%." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + local lftSlider = gui.verticalSlider(MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjLft) + + function lftSlider.update() + lftSlider.value = sliderPoint(lftCrv, lftOut, true) + end + + local rgtSlider = gui.verticalSlider(LCD_W - MARGIN, TOP, HEIGHT, 0, -750, 750, 10, adjRgt) + + function rgtSlider.update() + rgtSlider.value = sliderPoint(rgtCrv, rgtOut, false) + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + if gui ~= nil then + gui = nil + stepOff() + end +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = FindPoint() + ComputeYs(lftCrv, lftOut, lftYs) + reverse(lftYs) + ComputeYs(rgtCrv, rgtOut, rgtYs) + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/2/wing4.lua b/sdcard/c480x320/WIDGETS/SoarETX/2/wing4.lua new file mode 100644 index 00000000..99a3dafd --- /dev/null +++ b/sdcard/c480x320/WIDGETS/SoarETX/2/wing4.lua @@ -0,0 +1,383 @@ +--------------------------------------------------------------------------- +-- SoarETX flaps and aileron alignment, loadable component -- +-- -- +-- Author: Jesper Frickmann -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- +-- -- +-- Copyright (C) EdgeTX -- +-- -- +-- 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. -- +--------------------------------------------------------------------------- + +local widget, soarGlobals = ... +local libGUI = loadGUI() +libGUI.flags = MIDSIZE +local gui = nil +local colors = libGUI.colors +local title = "Wing alignment" +local modelType = "" + +-- Screen drawing constants +local HEADER = 40 +local TOP = 50 +local MARGIN = 20 +local DIST_X = 25 +local HEIGHT = 150 +local WIDTH = (LCD_W - 4.5 * DIST_X) / 4 +local TEXT_Y = 210 +local BUTTON_W = 80 +local BUTTON_X = LCD_W - BUTTON_W - MARGIN +local BUTTON_H = 36 +local BUTTON_Y = (LCD_H + TOP + HEIGHT - BUTTON_H) / 2 + +-- Other constants +local INP_STEP = getFieldInfo("input8").id -- Step input +local LS_STEP = nil -- Set this LS to apply step input and adjust +local GV_ADJUST = nil +local N = 5 -- Number of curve points +local MAX_Y = 1500 -- Max output value +local MINDIF = 100 -- Minimum difference between lower, center and upper values +local NC = 32 -- Number of channels + +-- Flaperon curve indices (LA, LF, RF, RA) +local CRV_IDX = { 0, 2, 3, 1 } +-- Tables with data for flaperon curves +local crvTbls = { {}, {}, {}, {} } +-- Indices of output channels +local outIds = { {}, {}, {}, {} } +-- Tables with data for flaperon output channels +local outTbls = { {}, {}, {}, {} } +-- Tables with y-values after both curve and output settings have been applied +local yVals = { {}, {}, {}, {} } +-- The point currently being edited +local activeP +-- Labels for curve plots +local labels = { + "Lft ail", + "Lft flp", + "Rgt flp", + "Rgt ail" +} + +-- Step Adjusting input has be turned on by this widget +local function isAdjustin() + local r = false + if (LS_STEP ~= nil) then r = getStickySwitch(LS_STEP) + elseif (GV_ADJUST ~= nil) then r = model.getGlobalVariable(GV_ADJUST, 0)==1 end + return r +end + +-- Turn off step input (if it was turned on by this widget) +local function stepOff() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, false) end + if (GV_ADJUST ~= nil) then model.setGlobalVariable(GV_ADJUST, 0, 0) end +end + +local function stepOn() + if (LS_STEP ~= nil) then setStickySwitch(LS_STEP, true) end + if (GV_ADJUST ~= nil) then model.setGlobalVariable(GV_ADJUST, 0, 1) end +end + +-- Make sure that we have the right number of points on the curve +local function GetCurve(crvIndex) + local tbl = soarGlobals.getCurve(crvIndex) + + if #tbl.y ~= N then + stepOff() + error("Wrong number of points on curve CV" .. crvIndex + 1) + end + + return tbl +end -- GetCurve() + +-- Find the output where the specified curve index is being used +local function GetOutput(crvIndex) + for i = 0, NC - 1 do + local out = model.getOutput(i) + + if out and out.curve == crvIndex then + return i, out + end + end + + stepOff() + error("No output channel with curve CV" .. crvIndex + 1) +end -- GetOutput() + +local function init() + for i, j in ipairs(CRV_IDX) do + crvTbls[i] = GetCurve(j) + outIds[i], outTbls[i] = GetOutput(j) + end + + stepOn() +end -- init() + +-- Find index of the curve point that corresponds to the value of the step input +local function FindPoint() + local x = getValue(INP_STEP) + return math.floor((N - 1) / 2048 * (x + 1024) + 1.5) +end -- FindPoint() + +-- Compute output after applying curve and center/endpoints +local function ComputeYs() + for i, j in ipairs(CRV_IDX) do + local crv = crvTbls[i] + local out = outTbls[i] + local y = yVals[i] + + for p = 1, N do + if crv.y[p] < 0 then + y[p] = out.offset + 0.01 * crv.y[p] * (out.offset - out.min) + else + y[p] = out.offset + 0.01 * crv.y[p] * (out.max - out.offset) + end + end + + if i <= 2 then + -- Reverse curve points on the left side + for k = 1, math.floor((N + 1) / 2) do + y[k], y[N + 1 - k] = -y[N + 1 - k], -y[k] + end + end + end +end -- ComputeYs() + +local function drawCurve(x, y, w, h, yValues) + -- Background and lines + gui.drawFilledRectangle(x, y, w + 1, h, colors.primary2) + gui.drawRectangle(x, y, w + 1, h, COLOR_THEME_SECONDARY2) + + gui.drawLine(x + 0.25 * w, y, x + 0.25 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.50 * w, y, x + 0.50 * w, y + h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x + 0.75 * w, y, x + 0.75 * w, y + h, DOTTED, COLOR_THEME_SECONDARY2) + + gui.drawLine(x, y + 0.1667 * h, x + w, y + 0.1667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.3333 * h, x + w, y + 0.3333 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.5000 * h, x + w, y + 0.5000 * h, SOLID, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.6667 * h, x + w, y + 0.6667 * h, DOTTED, COLOR_THEME_SECONDARY2) + gui.drawLine(x, y + 0.8333 * h, x + w, y + 0.8333 * h, DOTTED, COLOR_THEME_SECONDARY2) + + -- And now to the curve + local xs = { } + local ys = { } + + for i = 1, N do + xs[i] = x + math.floor(w * (i - 1) / (N - 1) + 0.5) + ys[i] = y + math.floor(h * 0.5 * (1 - yValues[i] / MAX_Y) + 0.5) + end + + for i = 2, N do + gui.drawLine(xs[i - 1], ys[i - 1], xs[i], ys[i], SOLID, COLOR_THEME_SECONDARY1, 3) + end + + for i = 1, N do + if i == activeP then + gui.drawFilledCircle(xs[i], ys[i], 4, colors.edit) + gui.drawCircle(xs[i], ys[i], 5, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 4, COLOR_THEME_SECONDARY1) + else + gui.drawFilledCircle(xs[i], ys[i], 2, colors.primary2) + gui.drawCircle(xs[i], ys[i], 3, COLOR_THEME_SECONDARY1) + gui.drawCircle(xs[i], ys[i], 2, COLOR_THEME_SECONDARY1) + end + end +end -- drawCurve() + +-- Adjustment is +/-750 around this offset +local function offset() + local ctr = (N + 1) / 2 + return (activeP - ctr) * 750 / (ctr - 1) +end + +-- Adjust a point, either on a curve or output +local function adjustPoint(i, slider) + local crvIdx = CRV_IDX[i] + local crvTbl = crvTbls[i] + local outIdx = outIds[i] + local outTbl = outTbls[i] + local activeP = activeP + local y = slider.value + offset() + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + y = -y + end + + if activeP == 1 then + outTbl.min = math.min(y, outTbl.offset - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == (N + 1) / 2 then + outTbl.offset = math.min(math.max(y, outTbl.min + MINDIF), outTbl.max - MINDIF) + model.setOutput(outIdx, outTbl) + elseif activeP == N then + outTbl.max = math.max(y, outTbl.offset + MINDIF) + model.setOutput(outIdx, outTbl) + else + crvTbl.y[activeP] = 0.1 * y + model.setCurve(crvIdx, crvTbl) + end +end + +-- The inverse function of adjust to set slider value from current settings +local function sliderPoint(i) + local crvTbl = crvTbls[i] + local outTbl = outTbls[i] + local activeP = activeP + local value + + if i <= 2 then + -- Left side; reverse + activeP = N + 1 - activeP + end + + if activeP == 1 then + value = outTbl.min + elseif activeP == (N + 1) / 2 then + value = outTbl.offset + elseif activeP == N then + value = outTbl.max + else + value = 10 * crvTbl.y[activeP] + end + + if i <= 2 then + value = -value + end + + return 10 * math.floor(0.1 * (value - offset()) + 0.5) +end + +-- Reset outputs +local function reset() + local midpt = (N + 1) / 2 + + for i, j in ipairs(CRV_IDX) do + local crvTbl = crvTbls[i] + for p = 1, N do + local y = 200.0 / (N - 1) * (p - midpt) + crvTbl.y[p] = y + end + model.setCurve(j, crvTbl) + + local outTbl = outTbls[i] + outTbl.min = -1000 + outTbl.offset = 0 + outTbl.max = 1000 + model.setOutput(outIds[i], outTbl) + end + + init() +end -- Reset() + +-------------------------------- Setup GUI -------------------------------- + +local function setup_gui() + gui = libGUI.newGUI() + + -- Extract Model Type from parametes + modelType = widget.options.Type + if modelType == "F3K_FH" then + LS_STEP = 10 -- L11 + elseif modelType == "F3J" or modelType == "F5J" then + GV_ADJUST = 7 -- GV8:Adj + else + LS_STEP = nil + modelType = "F??" + end + + function gui.fullScreenRefresh() + lcd.clear(COLOR_THEME_SECONDARY3) + + -- Top bar + lcd.drawFilledRectangle(0, 0, LCD_W, HEADER, COLOR_THEME_SECONDARY1) + lcd.drawText(10, 2, title.." "..modelType, bit32.bor(DBLSIZE, colors.primary2)) + + -- Curves + for i, j in ipairs(CRV_IDX) do + local x = (i - 1) * (DIST_X + WIDTH) + DIST_X + if i > 2 then + x = x - DIST_X / 2 + end + drawCurve(x, TOP, WIDTH, HEIGHT, yVals[i]) + lcd.drawText(x + 2, TOP, labels[i], SMLSIZE + colors.primary1) + end + + -- Help text + local txt = "Use the throttle stick to select a point on the\n" .. + "curve, and adjust with the sliders on the screen.\n" .. + "First end points, then center, and finally +/-50%." + lcd.drawTextLines(MARGIN, TEXT_Y, BUTTON_X - MARGIN, LCD_H - TEXT_Y, txt, colors.primary1) + end + + -- Close button + local buttonClose = gui.custom({ }, LCD_W - 34, 6, 28, 28) + + function buttonClose.draw(focused) + lcd.drawRectangle(LCD_W - 34, 6, 28, 28, colors.primary2) + lcd.drawText(LCD_W - 20, 20, "X", CENTER + VCENTER + MIDSIZE + colors.primary2) + + if focused then + buttonClose.drawFocus() + end + end + + function buttonClose.onEvent(event) + if event == EVT_VIRTUAL_ENTER then + lcd.exitFullScreen() + end + end + + -- Sliders + for i, j in ipairs(CRV_IDX) do + local x = DIST_X / 2 + (i - 1) * (DIST_X + WIDTH) + if i > 2 then + x = x + WIDTH + DIST_X / 2 + end + local slider = gui.verticalSlider(x, TOP, HEIGHT, 0, -750, 750, 10, function(slider) adjustPoint(i, slider) end) + + function slider.update() + slider.value = sliderPoint(i) + end + end + + gui.button(BUTTON_X, BUTTON_Y, BUTTON_W, BUTTON_H, "Reset", reset) +end -- Setup GUI + +-------------------- Background and Refresh functions --------------------- + +function widget.background() + gui=nil + stepOff() +end -- background() + +function widget.refresh(event, touchState) + if not event then + widget.background() + lcd.drawFilledRectangle(6, 6, widget.zone.w - 12, widget.zone.h - 12, colors.focus) + lcd.drawRectangle(7, 7, widget.zone.w - 14, widget.zone.h - 14, colors.primary2, 1) + lcd.drawText(widget.zone.w / 2, widget.zone.h / 2, title, CENTER + VCENTER + MIDSIZE + colors.primary2) + return + elseif gui == nil then + setup_gui() + init() + return + end + + activeP = FindPoint() + ComputeYs() + + gui.run(event, touchState) +end -- refresh(...) diff --git a/sdcard/c480x320/WIDGETS/SoarETX/main.lua b/sdcard/c480x320/WIDGETS/SoarETX/main.lua index 0db15de1..3ea2230e 100644 --- a/sdcard/c480x320/WIDGETS/SoarETX/main.lua +++ b/sdcard/c480x320/WIDGETS/SoarETX/main.lua @@ -2,8 +2,9 @@ -- SoarETX widget -- -- -- -- Author: Jesper Frickmann -- --- Date: 2022-02-08 -- --- Version: 1.0.0 -- +-- Improvements: Frankie Arzu -- +-- Date: 2024-01-15 -- +-- Version: 1.2.0 -- -- -- -- Copyright (C) EdgeTX -- -- -- @@ -21,10 +22,51 @@ local options = { { "Version", VALUE, 1, 1, 99 }, - { "FileName", STRING, "" } + { "FileName", STRING, "" }, + { "Type", STRING, "" } } + local soarGlobals +-- Battery - moved here from battery.lua because of bugs in ETX not calling background() on topbar widgets +local rxBatNxtWarn = 0 +local rxBatNxtCheck = 0 + +function rxBatCheck() + local now = getTime() + + if now < rxBatNxtCheck then + return + end + + rxBatNxtCheck = now + 100 + + local rxBatSrc = getFieldInfo("Cels") + if not rxBatSrc then rxBatSrc = getFieldInfo("RxBt") end + if not rxBatSrc then rxBatSrc = getFieldInfo("A1") end + if not rxBatSrc then rxBatSrc = getFieldInfo("A2") end + + if rxBatSrc then + soarGlobals.battery = getValue(rxBatSrc.id) + + if type(soarGlobals.battery) == "table" then + for i = 2, #soarGlobals.battery do + soarGlobals.battery[1] = math.min(soarGlobals.battery[1], soarGlobals.battery[i]) + end + soarGlobals.battery = soarGlobals.battery[1] + end + end + + -- Warn about low receiver battery + local rxBatMin = 0.1 * (soarGlobals.getParameter(soarGlobals.batteryParameter) + 100) + if now > rxBatNxtWarn and soarGlobals.battery > 0 and soarGlobals.battery < rxBatMin then + playHaptic(200, 0, 1) + playFile("lowbat.wav") + playNumber(10 * soarGlobals.battery + 0.5, 1, PREC1) + rxBatNxtWarn = now + 2000 + end +end -- rxBatCheck() + -- Load a Lua component dynamically based on option values local function Load(widget) local chunk, errMsg = loadScript(soarGlobals.path .. widget.options.Version .. "/" .. widget.options.FileName .. ".lua") @@ -35,21 +77,47 @@ local function Load(widget) end end +local function GetCurve(crvIndex) + local N = 5 + + local oldTbl = model.getCurve(crvIndex) + + if #oldTbl.y == N then -- Normal Behaviour + return oldTbl + end + + -- Work arround the bug of GetCurve in some versions (2.8.3) of ETX + if #oldTbl.y == N - 1 then + local newTbl = { } + newTbl.y = { } + for p = 1, N do + newTbl.y[p] = oldTbl.y[p - 1] + end + newTbl.smooth = 1 + newTbl.name = oldTbl.name + return newTbl + end + + return oldTbl +end -- GetCurve() + + -- Initialize the first time this widget is instantiated local function init() soarGlobals = { path = "/WIDGETS/SoarETX/", battery = 0, - batteryParameter = 1 + batteryParameter = 1, + getCurve = GetCurve } -- Functions to handle persistent model parameters stored in curve 32 - local parameterCurve = model.getCurve(31) + local parameterCurve = GetCurve(31) if not parameterCurve then error("Curve #32 is missing! It is used to store persistent model parameters for Lua.") end - + function soarGlobals.getParameter(idx) return parameterCurve.y[idx] end @@ -102,6 +170,8 @@ local function refresh(widget, event, touchState) end local function background(widget) + rxBatCheck() + if widget.background then widget.background() end