commit 933eee69e49ea54f9e80c1614d9fbcb0e2a8ddea Author: Annika Merris Date: Thu Jun 26 07:54:22 2025 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c7c974 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/FIRMWARE/*.bin +*.wav +.DS_Store diff --git a/BACKUP/CAR2-2023-10-06.yml b/BACKUP/CAR2-2023-10-06.yml new file mode 100755 index 0000000..f66dbd2 --- /dev/null +++ b/BACKUP/CAR2-2023-10-06.yml @@ -0,0 +1,682 @@ +semver: 2.10.0 +header: + name: "CAR2" +timers: + 0: + start: 300 + swtch: "L1" + value: 187 + mode: ON + countdownBeep: 2 + minuteBeep: 1 + persistent: 2 + countdownStart: 1 + showElapsed: 0 + extraHaptic: 0 + name: "Tsb" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 0 +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: "" + - + weight: 100 + destCh: 2 + srcRaw: I2 + 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: SB + 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: 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: 5 + 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: 6 + srcRaw: SC + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + offset: 0 + swtch: "NONE" + flightModes: 000000000 + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + weight: 100 + destCh: 7 + srcRaw: SD + 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: 1 + curve: 0 + name: "" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: TH + chn: 0 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: ST + chn: 1 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: SA + chn: 2 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: SB + chn: 3 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: P1 + chn: 4 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: P2 + chn: 5 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: SC + chn: 6 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: SD + chn: 7 + swtch: "NONE" + flightModes: 000000000 + weight: 100 + name: "" + offset: 0 + curve: + type: 1 + value: 0 +curves: + 31: + type: 1 + smooth: 0 + points: -1 + name: "CNT" +points: + 155: + val: -100 + 158: + val: 100 + 159: + val: -1 + 160: + val: 1 +logicalSw: + 0: + func: FUNC_STICKY + def: "SB0,SB0" + andsw: "NONE" + delay: 0 + duration: 0 + 1: + func: FUNC_VNEG + def: "I0,-5" + andsw: "NONE" + delay: 0 + duration: 0 + 2: + func: FUNC_VPOS + def: "TH,5" + andsw: "NONE" + delay: 0 + duration: 0 + 3: + func: FUNC_VNEG + def: "I0,-75" + andsw: "NONE" + delay: 0 + duration: 0 + 4: + func: FUNC_AND + def: "!L3,!L2" + andsw: "NONE" + delay: 0 + duration: 0 +customFn: + 0: + swtch: "L1" + func: PLAY_TRACK + def: "start,1x" + 1: + swtch: "!L1" + func: PLAY_TRACK + def: "stop,1x" + 2: + swtch: "L2" + func: RGB_LED + def: "red" + 3: + swtch: "L3" + func: RGB_LED + def: "blue" + 4: + swtch: "L4" + func: RGB_LED + def: "police" + 5: + swtch: "L5" + func: RGB_LED + def: "green" +thrTraceSrc: TH +switchWarningState: AuBuCuDu +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_CROSSFIRE + subType: 0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + crsf: + telemetryBaudrate: 0 +trainerData: + mode: SLAVE + channelsStart: 0 + channelsCount: 0 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "Th" + 1: + val: "St" + 2: + val: "Sa" + 3: + val: "Sb" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 20 + id2: + instance: 0 + label: "1RSS" + 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: 20 + id2: + instance: 1 + label: "2RSS" + 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: 20 + id2: + instance: 2 + label: "RQly" + subId: 0 + type: TYPE_CUSTOM + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 20 + id2: + instance: 3 + label: "RSNR" + 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: 20 + id2: + instance: 4 + label: "ANT" + 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 + 5: + id1: + id: 20 + id2: + instance: 5 + label: "RFMD" + 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: 20 + id2: + instance: 6 + label: "TPWR" + subId: 0 + type: TYPE_CUSTOM + unit: 16 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 7: + id1: + id: 20 + id2: + instance: 7 + 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 + 8: + id1: + id: 20 + id2: + instance: 8 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 9: + id1: + id: 20 + id2: + instance: 9 + label: "TSNR" + 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 + 10: + id1: + id: 8 + id2: + instance: 0 + label: "RxBt" + subId: 0 + type: TYPE_CUSTOM + unit: 1 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 11: + id1: + id: 8 + id2: + instance: 1 + label: "Curr" + subId: 0 + type: TYPE_CUSTOM + unit: 2 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 12: + id1: + id: 8 + id2: + instance: 2 + label: "Capa" + subId: 0 + type: TYPE_CUSTOM + unit: 14 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 13: + id1: + id: 8 + id2: + instance: 3 + label: "Bat%" + subId: 0 + type: TYPE_CUSTOM + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +screens: + 0: + type: VALUES + u: + lines: + 0: + sources: + 0: + val: tele(10) + 1: + val: tele(2) + 1: + sources: + 0: + val: Tmr1 + 1: + val: tele(6) +view: 0 +modelRegistrationID: "*\x15*\x15!\x03%\x07" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/FIRMWARE/readme.txt b/FIRMWARE/readme.txt new file mode 100755 index 0000000..13e3c64 --- /dev/null +++ b/FIRMWARE/readme.txt @@ -0,0 +1,2 @@ +You can put firmware for your modules or radio in this folder. +Files in this folder are NOT automatically applied. diff --git a/LOGS/readme.txt b/LOGS/readme.txt new file mode 100755 index 0000000..fb26ce7 --- /dev/null +++ b/LOGS/readme.txt @@ -0,0 +1 @@ +Logs files created by "SD Logs" special function will be stored in this directory. diff --git a/MODELS/README.txt b/MODELS/README.txt new file mode 100755 index 0000000..9ae65e5 --- /dev/null +++ b/MODELS/README.txt @@ -0,0 +1,3 @@ +Model configuration files go in this directory. On colorlcd radios, there is +also a `models.yml` file which controls which models are shown, and in what +order they are shown. diff --git a/MODELS/model00.yml b/MODELS/model00.yml new file mode 100644 index 0000000..eef3ee0 --- /dev/null +++ b/MODELS/model00.yml @@ -0,0 +1,525 @@ +semver: 2.11.1 +header: + name: KRATON + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +timers: + 0: + swtch: L1 + mode: OFF + name: "" + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: 0 + value: 297 + showElapsed: 0 + extraHaptic: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +checklistInteractive: 0 +flightModeData: + 0: + trim: + 3: + value: 2 + mode: 0 + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + swtch: "!L2" + name: Disarmed + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I0 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: I1 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" +expoData: + - srcRaw: ST + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" + - srcRaw: TH + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: St + 1: + val: Th +curves: + 31: + type: 1 + smooth: 0 + points: -1 + name: CNT +points: + 155: + val: -100 + 156: + val: 0 + 157: + val: 0 + 158: + val: 100 + 159: + val: -1 + 160: + val: 1 +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 +customFn: + 0: + swtch: "!L2" + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: TH + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 6,4 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 1 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +telemetrySensors: + 0: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 0 + label: 1RSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 1 + label: 2RSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 2: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 2 + label: RQly + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 3 + label: RSNR + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 4 + label: ANT + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 5 + label: RFMD + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 6 + label: TPWR + unit: 16 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 7: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 7 + label: TRSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 8: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 8 + label: TQly + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 9: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 9 + label: TSNR + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 10: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 0 + label: RxBt + unit: 1 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 11: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 1 + label: Curr + unit: 2 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 12: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 2 + label: Capa + unit: 14 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 13: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 3 + label: Bat + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +modelRegistrationID: "*\x15*\x15!\x03%\x07" +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model01.yml b/MODELS/model01.yml new file mode 100644 index 0000000..9d392ff --- /dev/null +++ b/MODELS/model01.yml @@ -0,0 +1,395 @@ +semver: 2.11.1 +header: + name: DT4.18 + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 0 +extendedTrims: 0 +throttleReversed: 1 +checklistInteractive: 0 +flightModeData: + 0: + trim: + 0: + value: 6 + mode: 0 + 4: + value: -2 + mode: 0 + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 100 + 1: + swtch: "!L2" + name: Disarm + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: I0 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 7 + srcRaw: P2 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Gyro +expoData: + - srcRaw: TH + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" + - srcRaw: ST + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: TH + 1: + val: ST +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 +customFn: + 0: + swtch: "!L2" + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: THR + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: ST + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +screens: + 0: + type: BARS + u: + bars: + 0: + source: tele(2) + barMin: 0 + barMax: 0 + 1: + source: tele(3) + barMin: 0 + barMax: 0 + 2: + source: tele(4) + barMin: 0 + barMax: 0 + 3: + source: tele(5) + barMin: 0 + barMax: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 74,0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +telemetrySensors: + 0: + type: TYPE_CUSTOM + id1: + id: 241 + subId: 0 + id2: + instance: 0 + label: A1 + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 1: + type: TYPE_CUSTOM + id1: + id: 242 + subId: 0 + id2: + instance: 0 + label: A2 + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 2: + type: TYPE_CUSTOM + id1: + id: 240 + subId: 0 + id2: + instance: 0 + label: RSSI + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + type: TYPE_CUSTOM + id1: + id: 65534 + subId: 0 + id2: + instance: 0 + label: TRSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + type: TYPE_CUSTOM + id1: + id: 65532 + subId: 0 + id2: + instance: 0 + label: RQly + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + type: TYPE_CUSTOM + id1: + id: 65533 + subId: 0 + id2: + instance: 0 + label: TQly + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +modelRegistrationID: ANNIKA +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model02.yml b/MODELS/model02.yml new file mode 100644 index 0000000..c6edb5d --- /dev/null +++ b/MODELS/model02.yml @@ -0,0 +1,550 @@ +semver: 2.11.1 +header: + name: ARX100 + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +timers: + 0: + swtch: L1 + mode: OFF + name: "" + minuteBeep: 0 + countdownBeep: 0 + start: 0 + persistent: 0 + countdownStart: 0 + value: 297 + showElapsed: 0 + extraHaptic: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 1 +extendedTrims: 0 +throttleReversed: 0 +checklistInteractive: 0 +flightModeData: + 0: + trim: + 0: + value: -82 + mode: 0 + 1: + value: -22 + mode: 0 + 4: + value: 6 + mode: 0 + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + swtch: "!L2" + name: Disarm + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I0 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 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 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 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: "" + curve: 0 + 1: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: TH + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + trimSource: 0 + name: "" + - srcRaw: ST + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 0 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: TH + 1: + val: ST +curves: + 31: + type: 1 + smooth: 0 + points: -1 + name: CNT +points: + 155: + val: -100 + 156: + val: 0 + 157: + val: 0 + 158: + val: 100 + 159: + val: -1 + 160: + val: 1 +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 +customFn: + 0: + swtch: "!L2" + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: THR + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 1,0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +telemetrySensors: + 0: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 0 + label: 1RSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 1: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 1 + label: 2RSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 2: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 2 + label: RQly + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 3 + label: RSNR + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 4 + label: ANT + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 5 + label: RFMD + unit: 0 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 6: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 6 + label: TPWR + unit: 16 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 7: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 7 + label: TRSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 8: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 8 + label: TQly + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 9: + type: TYPE_CUSTOM + id1: + id: 20 + subId: 0 + id2: + instance: 9 + label: TSNR + unit: 17 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 10: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 0 + label: RxBt + unit: 1 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 11: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 1 + label: Curr + unit: 2 + prec: 1 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 12: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 2 + label: Capa + unit: 14 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 13: + type: TYPE_CUSTOM + id1: + id: 8 + subId: 0 + id2: + instance: 3 + label: Bat + unit: 13 + prec: 0 + autoOffset: 0 + filter: 0 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +modelRegistrationID: "*\x15*\x15!\x03%\x07" +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model03.yml b/MODELS/model03.yml new file mode 100644 index 0000000..3a70801 --- /dev/null +++ b/MODELS/model03.yml @@ -0,0 +1,251 @@ +semver: 2.11.1 +header: + name: MOJAVE + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 0 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 0 +extendedTrims: 0 +throttleReversed: 0 +checklistInteractive: 0 +flightModeData: + 0: + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + swtch: "!L2" + name: Disarm + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: I0 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 3 + srcRaw: P2 + weight: 25 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: -10 + name: DSC +limitData: + 3: + min: 0 + max: 0 + revert: 0 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: TH + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" + - srcRaw: ST + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: TH + 1: + val: ST +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 +customFn: + 0: + swtch: L2 + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: TH + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 11,5 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +modelRegistrationID: MOJAVE +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model04.yml b/MODELS/model04.yml new file mode 100644 index 0000000..11a83e6 --- /dev/null +++ b/MODELS/model04.yml @@ -0,0 +1,232 @@ +semver: 2.11.1 +header: + name: GRANITE + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 0 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 0 +extendedTrims: 0 +throttleReversed: 0 +checklistInteractive: 0 +flightModeData: + 0: + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + swtch: "!L2" + name: Disarm + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I0 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 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 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" +limitData: + 1: + min: 0 + max: 0 + revert: 1 + offset: 0 + ppmCenter: 0 + symetrical: 0 + name: "" + curve: 0 +expoData: + - srcRaw: TH + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" + - srcRaw: ST + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: TH + 1: + val: ST +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 +customFn: + 0: + swtch: L2 + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: TH + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 1,0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +modelRegistrationID: ANNIKA +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model05.yml b/MODELS/model05.yml new file mode 100644 index 0000000..e25e028 --- /dev/null +++ b/MODELS/model05.yml @@ -0,0 +1,383 @@ +semver: 2.11.1 +header: + name: RAIDER + bitmap: "" + labels: "" + modelId: + 0: + val: 0 +noGlobalFunctions: 0 +thrTrim: 0 +trimInc: 0 +displayTrims: 2 +ignoreSensorIds: 0 +showInstanceIds: 0 +disableThrottleWarning: 0 +enableCustomThrottleWarning: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +extendedLimits: 0 +extendedTrims: 0 +throttleReversed: 0 +checklistInteractive: 0 +flightModeData: + 0: + trim: + 0: + value: -64 + mode: 0 + name: 100pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + swtch: "!L2" + name: Disarm + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + swtch: SA1 + name: 60pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + swtch: SA2 + name: 30pct + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +mixData: + - destCh: 0 + srcRaw: I1 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 1 + srcRaw: I0 + weight: gv(0) + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: "" + - destCh: 7 + srcRaw: P2 + weight: 100 + swtch: NONE + curve: + type: 0 + value: 0 + delayPrec: 0 + delayUp: 0 + delayDown: 0 + speedPrec: 0 + speedUp: 0 + speedDown: 0 + carryTrim: 0 + mltpx: ADD + mixWarn: 0 + flightModes: 000000000 + offset: 0 + name: Gyro +expoData: + - srcRaw: TH + scale: 0 + mode: 3 + chn: 0 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" + - srcRaw: ST + scale: 0 + mode: 3 + chn: 1 + swtch: NONE + flightModes: 000000000 + weight: 100 + offset: 0 + curve: + type: 1 + value: 0 + trimSource: 0 + name: "" +inputNames: + 0: + val: TH + 1: + val: ST +logicalSw: + 0: + func: FUNC_EDGE + def: SC2,0,- + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 0 + 1: + func: FUNC_STICKY + def: L1,L1 + delay: 0 + duration: 0 + andsw: NONE + lsPersist: 0 + lsState: 1 +customFn: + 0: + swtch: "!L2" + func: RGB_LED + def: rgbLop,1,On + 1: + swtch: SA0 + func: RGB_LED + def: green,1,On + 2: + swtch: SA1 + func: RGB_LED + def: yellow,1,On + 3: + swtch: SA2 + func: RGB_LED + def: orange,1,On +thrTraceSrc: TH +thrTrimSw: 0 +potsWarnMode: WARN_OFF +potsWarnEnabled: 0 +jitterFilter: GLOBAL +displayChecklist: 0 +gvars: + 0: + name: THR + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +telemetryProtocol: 0 +screens: + 0: + type: BARS + u: + bars: + 0: + source: tele(2) + barMin: 0 + barMax: 0 + 1: + source: tele(3) + barMin: 0 + barMax: 0 + 2: + source: tele(4) + barMin: 0 + barMax: 0 + 3: + source: tele(5) + barMin: 0 + barMax: 0 +varioData: + source: none + centerSilent: 0 + centerMax: 0 + centerMin: 0 + min: 0 + max: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +disableTelemetryWarning: 0 +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 74,0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +telemetrySensors: + 0: + type: TYPE_CUSTOM + id1: + id: 241 + subId: 0 + id2: + instance: 0 + label: A1 + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 1: + type: TYPE_CUSTOM + id1: + id: 242 + subId: 0 + id2: + instance: 0 + label: A2 + unit: 1 + prec: 1 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 132 + offset: 0 + 2: + type: TYPE_CUSTOM + id1: + id: 240 + subId: 0 + id2: + instance: 0 + label: RSSI + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + type: TYPE_CUSTOM + id1: + id: 65534 + subId: 0 + id2: + instance: 0 + label: TRSS + unit: 17 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + type: TYPE_CUSTOM + id1: + id: 65532 + subId: 0 + id2: + instance: 0 + label: RQly + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + type: TYPE_CUSTOM + id1: + id: 65533 + subId: 0 + id2: + instance: 0 + label: TQly + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +modelRegistrationID: ANNIKA +hatsMode: GLOBAL +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL \ No newline at end of file diff --git a/MODELS/model06.yml b/MODELS/model06.yml new file mode 100755 index 0000000..e888d01 --- /dev/null +++ b/MODELS/model06.yml @@ -0,0 +1,383 @@ +semver: 2.11.1 +header: + name: "RAIDER" +telemetryProtocol: 0 +thrTrim: 0 +noGlobalFunctions: 0 +displayTrims: 2 +ignoreSensorIds: 0 +trimInc: 0 +disableThrottleWarning: 0 +displayChecklist: 0 +extendedLimits: 0 +extendedTrims: 0 +throttleReversed: 0 +enableCustomThrottleWarning: 0 +disableTelemetryWarning: 0 +showInstanceIds: 0 +checklistInteractive: 0 +customThrottleWarningPosition: 0 +beepANACenter: 0 +mixData: + - + destCh: 0 + srcRaw: "I1" + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + delayPrec: 0 + speedPrec: 0 + flightModes: 000000000 + weight: 100 + offset: 0 + swtch: "NONE" + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + destCh: 1 + srcRaw: "I0" + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + delayPrec: 0 + speedPrec: 0 + flightModes: 000000000 + weight: 100 + offset: 0 + swtch: "NONE" + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "" + - + destCh: 7 + srcRaw: "P2" + carryTrim: 0 + mixWarn: 0 + mltpx: ADD + delayPrec: 0 + speedPrec: 0 + flightModes: 000000000 + weight: 100 + offset: 0 + swtch: "NONE" + delayUp: 0 + delayDown: 0 + speedUp: 0 + speedDown: 0 + name: "Gyro" +expoData: + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: "TH" + weight: "gv(0)" + offset: 0 + swtch: "NONE" + curve: + type: 1 + value: 0 + chn: 0 + flightModes: 000000000 + name: "" + - + mode: 3 + scale: 0 + trimSource: 0 + srcRaw: "ST" + weight: "gv(1)" + offset: 0 + swtch: "NONE" + curve: + type: 1 + value: 0 + chn: 1 + flightModes: 000000000 + name: "" +logicalSw: + 0: + func: FUNC_EDGE + def: "SC2,0,-" + andsw: "NONE" + lsPersist: 0 + lsState: 0 + delay: 0 + duration: 0 + 1: + func: FUNC_STICKY + def: "L1,L1" + andsw: "NONE" + lsPersist: 0 + lsState: 1 + delay: 0 + duration: 0 +flightModeData: + 0: + trim: + 0: + value: -64 + mode: 0 + name: "No Lim" + swtch: "NONE" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 100 + 1: + val: 100 + 2: + val: 0 + 3: + val: 0 + 4: + val: 0 + 5: + val: 0 + 6: + val: 0 + 7: + val: 0 + 8: + val: 0 + 1: + name: "Disarm" + swtch: "!L2" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 0 + 1: + val: 0 + 2: + name: "60 Lim" + swtch: "SA1" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 60 + 3: + name: "30 Lim" + swtch: "SA2" + fadeIn: 0 + fadeOut: 0 + gvars: + 0: + val: 30 +thrTraceSrc: TH +switchWarning: + SA: + pos: up + FL1: + pos: up + FL2: + pos: up +gvars: + 0: + name: "THR" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 + 1: + name: "ST" + min: 0 + max: 0 + popup: 0 + prec: 0 + unit: 0 +rssiSource: none +rfAlarms: + warning: 45 + critical: 42 +thrTrimSw: 0 +potsWarnMode: WARN_OFF +jitterFilter: GLOBAL +moduleData: + 0: + type: TYPE_MULTIMODULE + subType: 74,0 + channelsStart: 0 + channelsCount: 16 + failsafeMode: NOT_SET + mod: + multi: + disableTelemetry: 0 + disableMapping: 0 + autoBindMode: 0 + lowPowerMode: 0 + receiverTelemetryOff: 0 + receiverHigherChannels: 0 + optionValue: 0 +trainerData: + mode: OFF + channelsStart: 0 + channelsCount: -8 + frameLength: 0 + delay: 0 + pulsePol: 0 +inputNames: + 0: + val: "TH" + 1: + val: "ST" +potsWarnEnabled: 0 +telemetrySensors: + 0: + id1: + id: 241 + id2: + instance: 0 + label: "A1" + 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 + 1: + id1: + id: 242 + id2: + instance: 0 + 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: 240 + id2: + instance: 0 + label: "RSSI" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 3: + id1: + id: 65534 + id2: + instance: 0 + label: "TRSS" + subId: 0 + type: TYPE_CUSTOM + unit: 17 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 4: + id1: + id: 65532 + id2: + instance: 0 + label: "RQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 + 5: + id1: + id: 65533 + id2: + instance: 0 + label: "TQly" + subId: 0 + type: TYPE_CUSTOM + unit: 0 + prec: 0 + autoOffset: 0 + filter: 1 + logs: 1 + persistent: 0 + onlyPositive: 0 + cfg: + custom: + ratio: 0 + offset: 0 +screens: + 0: + type: BARS + u: + bars: + 0: + source: tele(2) + barMin: 0 + barMax: 0 + 1: + source: tele(3) + barMin: 0 + barMax: 0 + 2: + source: tele(4) + barMin: 0 + barMax: 0 + 3: + source: tele(5) + barMin: 0 + barMax: 0 +view: 0 +modelRegistrationID: "ANNIKA" +usbJoystickExtMode: 0 +usbJoystickIfMode: JOYSTICK +usbJoystickCircularCut: 0 +radioGFDisabled: GLOBAL +radioTrainerDisabled: GLOBAL +modelHeliDisabled: GLOBAL +modelFMDisabled: GLOBAL +modelCurvesDisabled: GLOBAL +modelGVDisabled: GLOBAL +modelLSDisabled: GLOBAL +modelSFDisabled: GLOBAL +modelCustomScriptsDisabled: GLOBAL +modelTelemetryDisabled: GLOBAL diff --git a/RADIO/README.txt b/RADIO/README.txt new file mode 100755 index 0000000..7da16a9 --- /dev/null +++ b/RADIO/README.txt @@ -0,0 +1 @@ +Radio specific configuration files are stored in this directory. diff --git a/RADIO/radio.yml b/RADIO/radio.yml new file mode 100755 index 0000000..2ba9719 --- /dev/null +++ b/RADIO/radio.yml @@ -0,0 +1,183 @@ +checksum: 12551 +semver: 2.11.1 +board: mt12 +calib: + ST: + mid: 1052 + spanNeg: 703 + spanPos: 743 + TH: + mid: 764 + spanNeg: 560 + spanPos: 1012 + P1: + mid: 1023 + spanNeg: 1005 + spanPos: 1007 + P2: + mid: 1026 + spanNeg: 1008 + spanPos: 1004 + P3: + mid: 935 + spanNeg: 664 + spanPos: 543 + P4: + mid: 1099 + spanNeg: 631 + spanPos: 561 +currModelFilename: model1.yml +vBatWarn: 66 +txVoltageCalibration: -7 +vBatMin: 64 +vBatMax: 84 +backlightColor: 0 +contrast: 18 +currModel: 0 +backlightMode: backlight_mode_all +trainer: + calib: + 0: + val: 0 + 1: + val: 0 + 2: + val: 0 + 3: + val: 0 + mix: + 0: + srcChn: 3 + mode: REPL + studWeight: 100 + 1: + srcChn: 1 + mode: REPL + studWeight: 100 + 2: + srcChn: 2 + mode: REPL + studWeight: 100 + 3: + srcChn: 0 + mode: REPL + studWeight: 100 +PPM_Multiplier: 0 +view: 1 +fai: 0 +disableMemoryWarning: 0 +beepMode: mode_all +alarmsFlash: 0 +disableAlarmWarning: 0 +disableRssiPoweroffAlarm: 0 +disableTrainerPoweroffAlarm: 0 +USBMode: 0 +hatsMode: SWITCHABLE +stickDeadZone: 0 +jackMode: 0 +hapticMode: mode_nokeys +stickMode: 1 +timezone: -5 +timezoneMinutes: 0 +adjustRTC: 1 +inactivityTimer: 30 +internalModuleBaudrate: 5 +internalModule: TYPE_MULTIMODULE +splashMode: 2 +lightAutoOff: 12 +templateSetup: 21 +hapticLength: 1 +speakerPitch: 0 +hapticStrength: 2 +beepLength: 2 +gpsFormat: 0 +speakerVolume: 4 +backlightBright: 0 +blOffBright: 0 +switchesDelay: 0 +globalTimer: 43671 +bluetoothName: 94832Q- +bluetoothBaudrate: 0 +bluetoothMode: OFF +countryCode: 0 +noJitterFilter: 0 +disableRtcWarning: 1 +audioMuteEnable: 0 +keysBacklight: 0 +rotEncMode: 0 +imperial: 0 +ppmunit: 0 +ttsLanguage: en +beepVolume: 4 +wavVolume: 4 +varioVolume: 2 +varioPitch: 0 +varioRange: 0 +varioRepeat: 0 +backgroundVolume: 3 +dontPlayHello: 0 +invertLCD: 0 +serialPort: + VCP: + mode: CLI + power: 0 +antennaMode: MODE_PER_MODEL +pwrOnSpeed: 1 +pwrOffSpeed: 1 +pwrOffIfInactive: 0 +disablePwrOnOffHaptic: 0 +sticksConfig: + 0: + name: "" + 1: + name: "" +potsConfig: + P1: + name: "" + type: with_detent + inv: 0 + P2: + name: "" + type: with_detent + inv: 0 + P3: + name: "" + type: axis_x + inv: 0 + P4: + name: "" + type: axis_y + inv: 0 +switchConfig: + SA: + type: 3pos + name: "" + SB: + type: toggle + name: "" + SC: + type: toggle + name: "" + SD: + type: toggle + name: "" + FL1: + type: 2pos + name: "" + FL2: + type: 2pos + name: "" +ownerRegistrationID: ANNIKA +imuMax: 0 +imuOffset: 0 +uartSampleMode: 0 +radioGFDisabled: 0 +radioTrainerDisabled: 0 +modelHeliDisabled: 0 +modelFMDisabled: 0 +modelCurvesDisabled: 0 +modelGVDisabled: 0 +modelLSDisabled: 0 +modelSFDisabled: 0 +modelCustomScriptsDisabled: 0 +modelTelemetryDisabled: 0 \ No newline at end of file diff --git a/SCREENSHOTS/readme.txt b/SCREENSHOTS/readme.txt new file mode 100755 index 0000000..59e528e --- /dev/null +++ b/SCREENSHOTS/readme.txt @@ -0,0 +1 @@ +Screenshots created by "Screenshot" special function will be stored in this directory. diff --git a/SCRIPTS/FUNCTIONS/readme.txt b/SCRIPTS/FUNCTIONS/readme.txt new file mode 100755 index 0000000..cabcbeb --- /dev/null +++ b/SCRIPTS/FUNCTIONS/readme.txt @@ -0,0 +1 @@ +This directory is for Lua functions scripts. diff --git a/SCRIPTS/MIXES/readme.txt b/SCRIPTS/MIXES/readme.txt new file mode 100755 index 0000000..2f3fd0a --- /dev/null +++ b/SCRIPTS/MIXES/readme.txt @@ -0,0 +1 @@ +This directory is for Lua mixer scripts. diff --git a/SCRIPTS/RGBLED/Bback.lua b/SCRIPTS/RGBLED/Bback.lua new file mode 100755 index 0000000..e39510a --- /dev/null +++ b/SCRIPTS/RGBLED/Bback.lua @@ -0,0 +1,68 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 + currentLed = 0 -- Current lit LED position + scroll_oldtime = getTime() -- Initialize scroll_oldtime + scroll_cycle = 0 -- Initialize scroll_cycle +end + +-- Function to generate smooth cyclic colors +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = 0, 0, 0 + local maxBrightness = 255 -- Maximum brightness value + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + -- Skip colors that are close to the background color + local bg_r, bg_g, bg_b = 0, 0, 72 -- Background color + local threshold = 30 -- Color difference threshold + if math.abs(r - bg_r) < threshold and math.abs(g - bg_g) < threshold and math.abs(b - bg_b) < threshold then + return getColor((phase + 1) % length, length) -- Skip this color and get the next one + end + + return r, g, b +end + +local colorPhase = 0 -- Initialize color phase + +local function run() + for i=LED_STRIP_LENGTH - 1, 0, -1 do -- Reverse iteration + if (i == scroll_cycle) then + local r, g, b = getColor(colorPhase, 255) + setRGBLedColor(i, r, g, b) + else + setRGBLedColor(i, 0, 0, 72) + end + end + if ((getTime() - scroll_oldtime) > 8) then + scroll_oldtime = getTime() + scroll_cycle = scroll_cycle - 1 -- Decrement scroll_cycle + if (scroll_cycle < 0) then + scroll_cycle = LED_STRIP_LENGTH - 1 -- Reset scroll_cycle to the end of the strip + end + end + colorPhase = (colorPhase + 1) % 255 -- Update color phase + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/Bfwrd.lua b/SCRIPTS/RGBLED/Bfwrd.lua new file mode 100755 index 0000000..6e66669 --- /dev/null +++ b/SCRIPTS/RGBLED/Bfwrd.lua @@ -0,0 +1,68 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 + currentLed = 0 -- Current lit LED position + scroll_oldtime = getTime() -- Initialize scroll_oldtime + scroll_cycle = 0 -- Initialize scroll_cycle +end + +-- Function to generate smooth cyclic colors +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = 0, 0, 0 + local maxBrightness = 255 -- Maximum brightness value + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + -- Skip colors that are close to the background color + local bg_r, bg_g, bg_b = 0, 0, 72 -- Background color + local threshold = 30 -- Color difference threshold + if math.abs(r - bg_r) < threshold and math.abs(g - bg_g) < threshold and math.abs(b - bg_b) < threshold then + return getColor((phase + 1) % length, length) -- Skip this color and get the next one + end + + return r, g, b +end + +local colorPhase = 0 -- Initialize color phase + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 do + if (i == scroll_cycle) then + local r, g, b = getColor(colorPhase, 255) + setRGBLedColor(i, r, g, b) + else + setRGBLedColor(i, 0, 0, 72) + end + end + if ((getTime() - scroll_oldtime) > 8) then + scroll_oldtime = getTime() + scroll_cycle = scroll_cycle + 1 + if (scroll_cycle >= LED_STRIP_LENGTH) then + scroll_cycle = 0 + end + end + colorPhase = (colorPhase + 1) % 255 -- Update color phase + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/Pback.lua b/SCRIPTS/RGBLED/Pback.lua new file mode 100755 index 0000000..54d21c4 --- /dev/null +++ b/SCRIPTS/RGBLED/Pback.lua @@ -0,0 +1,68 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 + currentLed = 0 -- Current lit LED position + scroll_oldtime = getTime() -- Initialize scroll_oldtime + scroll_cycle = 0 -- Initialize scroll_cycle +end + +-- Function to generate smooth cyclic colors +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = 0, 0, 0 + local maxBrightness = 255 -- Maximum brightness value + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + -- Skip colors that are close to the background color + local bg_r, bg_g, bg_b = 72, 0, 72 -- Background color + local threshold = 30 -- Color difference threshold + if math.abs(r - bg_r) < threshold and math.abs(g - bg_g) < threshold and math.abs(b - bg_b) < threshold then + return getColor((phase + 1) % length, length) -- Skip this color and get the next one + end + + return r, g, b +end + +local colorPhase = 0 -- Initialize color phase + +local function run() + for i=LED_STRIP_LENGTH - 1, 0, -1 do -- Reverse iteration + if (i == scroll_cycle) then + local r, g, b = getColor(colorPhase, 255) + setRGBLedColor(i, r, g, b) + else + setRGBLedColor(i, 72, 0, 72) + end + end + if ((getTime() - scroll_oldtime) > 8) then + scroll_oldtime = getTime() + scroll_cycle = scroll_cycle - 1 -- Decrement scroll_cycle + if (scroll_cycle < 0) then + scroll_cycle = LED_STRIP_LENGTH - 1 -- Reset scroll_cycle to the end of the strip + end + end + colorPhase = (colorPhase + 1) % 255 -- Update color phase + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/Pback.luac b/SCRIPTS/RGBLED/Pback.luac new file mode 100755 index 0000000..463db5d Binary files /dev/null and b/SCRIPTS/RGBLED/Pback.luac differ diff --git a/SCRIPTS/RGBLED/Pfwrd.lua b/SCRIPTS/RGBLED/Pfwrd.lua new file mode 100755 index 0000000..33e9008 --- /dev/null +++ b/SCRIPTS/RGBLED/Pfwrd.lua @@ -0,0 +1,68 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 + currentLed = 0 -- Current lit LED position + scroll_oldtime = getTime() -- Initialize scroll_oldtime + scroll_cycle = 0 -- Initialize scroll_cycle +end + +-- Function to generate smooth cyclic colors +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = 0, 0, 0 + local maxBrightness = 255 -- Maximum brightness value + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + -- Skip colors that are close to the background color + local bg_r, bg_g, bg_b = 72, 0, 72 -- Background color + local threshold = 30 -- Color difference threshold + if math.abs(r - bg_r) < threshold and math.abs(g - bg_g) < threshold and math.abs(b - bg_b) < threshold then + return getColor((phase + 1) % length, length) -- Skip this color and get the next one + end + + return r, g, b +end + +local colorPhase = 0 -- Initialize color phase + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 do + if (i == scroll_cycle) then + local r, g, b = getColor(colorPhase, 255) + setRGBLedColor(i, r, g, b) + else + setRGBLedColor(i, 72, 0, 72) + end + end + if ((getTime() - scroll_oldtime) > 8) then + scroll_oldtime = getTime() + scroll_cycle = scroll_cycle + 1 + if (scroll_cycle >= LED_STRIP_LENGTH) then + scroll_cycle = 0 + end + end + colorPhase = (colorPhase + 1) % 255 -- Update color phase + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/Pfwrd.luac b/SCRIPTS/RGBLED/Pfwrd.luac new file mode 100755 index 0000000..43f021c Binary files /dev/null and b/SCRIPTS/RGBLED/Pfwrd.luac differ diff --git a/SCRIPTS/RGBLED/README.md b/SCRIPTS/RGBLED/README.md new file mode 100755 index 0000000..c6a84d3 --- /dev/null +++ b/SCRIPTS/RGBLED/README.md @@ -0,0 +1 @@ +This folder contains sample RGB Lua scripts, for radios which support this capability. diff --git a/SCRIPTS/RGBLED/blue.lua b/SCRIPTS/RGBLED/blue.lua new file mode 100755 index 0000000..5c7f6a5 --- /dev/null +++ b/SCRIPTS/RGBLED/blue.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 0, 0, 128) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/blue.luac b/SCRIPTS/RGBLED/blue.luac new file mode 100755 index 0000000..946f800 Binary files /dev/null and b/SCRIPTS/RGBLED/blue.luac differ diff --git a/SCRIPTS/RGBLED/flow.lua b/SCRIPTS/RGBLED/flow.lua new file mode 100755 index 0000000..50fa082 --- /dev/null +++ b/SCRIPTS/RGBLED/flow.lua @@ -0,0 +1,52 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 +end + +local minBrightness = 0 -- Minimum brightness value +local maxBrightness = 255 -- Maximum brightness value + +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = minBrightness, minBrightness, minBrightness + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 32 * position) + g = maxBrightness * (32 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 32 * position) + b = maxBrightness * (32 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 32 * position) + r = maxBrightness * (32 * position) + end + + return r, g, b +end + +local colorChangeTime = 0 -- The time of the last color change + +local function run() + if ((getTime() - colorChangeTime) > 1) then -- Use an interval of 2 time units + colorChangeTime = getTime() + phase = (phase + 1) % 255 -- Update color phase + + for i = 0, LED_STRIP_LENGTH - 1, 1 do + local r, g, b = getColor(phase + i * 64, 255) -- Increase phase offset for each LED + setRGBLedColor(i, r, g, b) + end + applyRGBLedColors() + end +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/green.lua b/SCRIPTS/RGBLED/green.lua new file mode 100755 index 0000000..feb5310 --- /dev/null +++ b/SCRIPTS/RGBLED/green.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 0, 255, 0) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/green.luac b/SCRIPTS/RGBLED/green.luac new file mode 100755 index 0000000..3f5b5fa Binary files /dev/null and b/SCRIPTS/RGBLED/green.luac differ diff --git a/SCRIPTS/RGBLED/off.lua b/SCRIPTS/RGBLED/off.lua new file mode 100755 index 0000000..ec63dcc --- /dev/null +++ b/SCRIPTS/RGBLED/off.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 0, 0, 0) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/orange.lua b/SCRIPTS/RGBLED/orange.lua new file mode 100755 index 0000000..cf1650e --- /dev/null +++ b/SCRIPTS/RGBLED/orange.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 255, 100, 0) -- Change RGB values to represent orange color + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/orange.luac b/SCRIPTS/RGBLED/orange.luac new file mode 100644 index 0000000..36c5d95 Binary files /dev/null and b/SCRIPTS/RGBLED/orange.luac differ diff --git a/SCRIPTS/RGBLED/police.lua b/SCRIPTS/RGBLED/police.lua new file mode 100755 index 0000000..07dea0d --- /dev/null +++ b/SCRIPTS/RGBLED/police.lua @@ -0,0 +1,26 @@ +local function init() + police_oldtime = getTime() + police_cycle = 0 +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + if (i % 2 == police_cycle) then + setRGBLedColor(i, 0, 0, 50) + else + setRGBLedColor(i, 50, 0, 0) + end + end + if ((getTime() - police_oldtime) > 8) then + police_oldtime = getTime() + police_cycle = 1 - police_cycle + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/police.luac b/SCRIPTS/RGBLED/police.luac new file mode 100755 index 0000000..86fb644 Binary files /dev/null and b/SCRIPTS/RGBLED/police.luac differ diff --git a/SCRIPTS/RGBLED/purple.lua b/SCRIPTS/RGBLED/purple.lua new file mode 100755 index 0000000..99c6e19 --- /dev/null +++ b/SCRIPTS/RGBLED/purple.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 255, 0, 255) -- Set to purple color + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/rainbw.lua b/SCRIPTS/RGBLED/rainbw.lua new file mode 100755 index 0000000..5248ec7 --- /dev/null +++ b/SCRIPTS/RGBLED/rainbw.lua @@ -0,0 +1,52 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 +end + +local minBrightness = 0 -- Minimum brightness value +local maxBrightness = 255 -- Maximum brightness value + +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = minBrightness, minBrightness, minBrightness + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + return r, g, b +end + +local colorChangeTime = 0 -- The time of the last color change + +local function run() + if ((getTime() - colorChangeTime) > 2) then -- Use an interval of 4 time units + colorChangeTime = getTime() + phase = (phase + 1) % 255 -- Update color phase + + for i = 0, LED_STRIP_LENGTH - 1, 1 do + local r, g, b = getColor(phase + i * 64, 255) -- Increase phase offset for each LED + setRGBLedColor(i, r, g, b) + end + applyRGBLedColors() + end +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/rainbw.luac b/SCRIPTS/RGBLED/rainbw.luac new file mode 100755 index 0000000..e6b218f Binary files /dev/null and b/SCRIPTS/RGBLED/rainbw.luac differ diff --git a/SCRIPTS/RGBLED/red.lua b/SCRIPTS/RGBLED/red.lua new file mode 100755 index 0000000..05e8bd5 --- /dev/null +++ b/SCRIPTS/RGBLED/red.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 50, 0, 0) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/red.luac b/SCRIPTS/RGBLED/red.luac new file mode 100755 index 0000000..61f9cf4 Binary files /dev/null and b/SCRIPTS/RGBLED/red.luac differ diff --git a/SCRIPTS/RGBLED/rgbLop.lua b/SCRIPTS/RGBLED/rgbLop.lua new file mode 100755 index 0000000..3c70083 --- /dev/null +++ b/SCRIPTS/RGBLED/rgbLop.lua @@ -0,0 +1,53 @@ +local function init() + cycleTime = getTime() -- Initialize time + phase = 0 +end + +-- Function to generate smooth cyclic colors +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = 5, 5, 5 + local maxBrightness = 255 -- Maximum brightness value + local minBrightness = 0 -- Minimum brightness value + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = minBrightness + (maxBrightness - minBrightness) * (1 - 3 * position) + g = maxBrightness * (3 * position) + b = minBrightness + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = minBrightness + (maxBrightness - minBrightness) * (1 - 3 * position) + b = maxBrightness * (3 * position) + r = minBrightness + else + -- From blue to red + position = position - 2/3 + b = minBrightness + (maxBrightness - minBrightness) * (1 - 3 * position) + r = maxBrightness * (3 * position) + g = minBrightness + end + + return math.max(0, math.min(r, maxBrightness)), math.max(0, math.min(g, maxBrightness)), math.max(0, math.min(b, maxBrightness)) +end + +local function run() + if ((getTime() - cycleTime) > 2) then -- Use an interval of 8 time units + cycleTime = getTime() + phase = phase + 1 -- Update color phase + end + + for i = 0, LED_STRIP_LENGTH - 1, 1 do + local r, g, b = getColor(phase, 255) + setRGBLedColor(i, r, g, b) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/rgbLop.luac b/SCRIPTS/RGBLED/rgbLop.luac new file mode 100644 index 0000000..c2bde1f Binary files /dev/null and b/SCRIPTS/RGBLED/rgbLop.luac differ diff --git a/SCRIPTS/RGBLED/runner.lua b/SCRIPTS/RGBLED/runner.lua new file mode 100755 index 0000000..4139071 --- /dev/null +++ b/SCRIPTS/RGBLED/runner.lua @@ -0,0 +1,77 @@ +local function init() + colorChangeTime = getTime() -- Initialize time + phase = 0 + currentLed = 0 -- Current lit LED position +end + +local minBrightness = 0 -- Minimum brightness value +local maxBrightness = 255 -- Maximum brightness value + +local function getColor(phase, length) + local position = (phase % length) / length + local r, g, b = minBrightness, minBrightness, minBrightness + + -- RGB color transition: red -> green -> blue -> red + if position < 1/3 then + -- From red to green + r = maxBrightness * (1 - 3 * position) + g = maxBrightness * (3 * position) + elseif position < 2/3 then + -- From green to blue + position = position - 1/3 + g = maxBrightness * (1 - 3 * position) + b = maxBrightness * (3 * position) + else + -- From blue to red + position = position - 2/3 + b = maxBrightness * (1 - 3 * position) + r = maxBrightness * (3 * position) + end + + return r, g, b +end + +local maxBackgroundBrightness = 255 -- Maximum brightness value for the background + +local function run() + if ((getTime() - colorChangeTime) > 2) then -- Use an interval of 4 time units + colorChangeTime = getTime() + phase = phase + 1 -- Update color phase + currentLed = (currentLed + 1) % LED_STRIP_LENGTH -- Move to the next LED + end + + for i = 0, LED_STRIP_LENGTH - 1, 1 do + local r, g, b = getColor(phase, 255) + if i <= currentLed then + setRGBLedColor(i, r, g, b) + else + -- Set the background color to the opposite of the main color in the RGB color space + local bg_r = (r + 128) % 256 + local bg_g = (g + 128) % 256 + local bg_b = (b + 128) % 256 + + -- Ensure the brightness of the background color does not exceed 72 + bg_r = math.min(bg_r, maxBackgroundBrightness) + bg_g = math.min(bg_g, maxBackgroundBrightness) + bg_b = math.min(bg_b, maxBackgroundBrightness) + + -- Ensure at least one color channel is always off + if bg_r > bg_g and bg_r > bg_b then + bg_r = 0 + elseif bg_g > bg_r and bg_g > bg_b then + bg_g = 0 + else + bg_b = 0 + end + + setRGBLedColor(i, bg_r, bg_g, bg_b) + end + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/runner.luac b/SCRIPTS/RGBLED/runner.luac new file mode 100755 index 0000000..5241086 Binary files /dev/null and b/SCRIPTS/RGBLED/runner.luac differ diff --git a/SCRIPTS/RGBLED/sapp.lua b/SCRIPTS/RGBLED/sapp.lua new file mode 100755 index 0000000..151af46 --- /dev/null +++ b/SCRIPTS/RGBLED/sapp.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 0, 255, 255) -- Set to sapphire color + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/white.lua b/SCRIPTS/RGBLED/white.lua new file mode 100755 index 0000000..78e27c4 --- /dev/null +++ b/SCRIPTS/RGBLED/white.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 255, 255, 255) -- Set to white color + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } \ No newline at end of file diff --git a/SCRIPTS/RGBLED/yellow.lua b/SCRIPTS/RGBLED/yellow.lua new file mode 100755 index 0000000..f0176e7 --- /dev/null +++ b/SCRIPTS/RGBLED/yellow.lua @@ -0,0 +1,16 @@ +local function init() +end + +local function run() + for i=0, LED_STRIP_LENGTH - 1, 1 + do + setRGBLedColor(i, 255, 255, 0) + end + applyRGBLedColors() +end + +local function background() + -- Called periodically while the Special Function switch is off +end + +return { run=run, background=background, init=init } diff --git a/SCRIPTS/RGBLED/yellow.luac b/SCRIPTS/RGBLED/yellow.luac new file mode 100644 index 0000000..e3d0a97 Binary files /dev/null and b/SCRIPTS/RGBLED/yellow.luac differ diff --git a/SCRIPTS/TELEMETRY/gplusl.lua b/SCRIPTS/TELEMETRY/gplusl.lua new file mode 100755 index 0000000..4129315 --- /dev/null +++ b/SCRIPTS/TELEMETRY/gplusl.lua @@ -0,0 +1,63 @@ +-- This code was originally written by Miami Mike to calculate the Open Location Code (Google+Code) +-- It was altered by ChrisOhara to permanently store the last received GPS coordinates by background function. +-- So that it can display the last position as Google+Code even after connection to receiver is lost. +-- Works on taranis + +local mid = LCD_W / 2 +local map = {[0] = + "2", "3", "4", "5", "6", "7", "8", "9", "C", "F", + "G", "H", "J", "M", "P", "Q", "R", "V", "W", "X"} + +local my_gpsId +local latitude, longitude = 0.0, 0.0 +local lat = 0 +local lon = 0 +local pluscode = "" + + +local function init_func() + my_gpsId = getFieldInfo("GPS") and getFieldInfo("GPS").id or nil; +end + + +local function getcode(lat, lon) + local int = math.floor(lat) + local codepair = map[int] + lat = 20 * (lat - int) + int = math.floor(lon) + codepair = codepair .. map[int] + lon = 20 * (lon - int) + return lat, lon, codepair +end + + +local function bg_func() + if getValue(my_gpsId) ~= 0 then + local gps = getValue(my_gpsId) + latitude, longitude = gps.lat, gps.lon + end +end + + +local function run_func() + lat = (latitude + 90) / 20 + lon = (longitude + 180) / 20 + pluscode = "" + for i = 1, 4 do + lat, lon, codepair = getcode(lat, lon) + pluscode = pluscode .. codepair + end + pluscode = pluscode .. "+" + lat, lon, codepair = getcode(lat, lon) + pluscode = pluscode .. codepair + pluscode = pluscode .. map[4 * math.floor(lat / 5) + math.floor(lon / 4)] + lcd.clear() + lcd.drawText(mid - 53, 5, "GPS coordinates are") + lcd.drawText(mid - 44, 15, latitude.. ", " .. longitude) + lcd.drawText(mid- 49, 35, "Google Plus Code is") + lcd.drawText(mid - 32, 45, pluscode) -- full 12 characters + --- lcd.drawText(mid - 20, 45, string.sub(pluscode, 5, 12)) -- shortened version + return 0 +end + +return {run=run_func, init=init_func, background=bg_func} \ No newline at end of file diff --git a/SCRIPTS/TELEMETRY/readme.txt b/SCRIPTS/TELEMETRY/readme.txt new file mode 100755 index 0000000..ea20c78 --- /dev/null +++ b/SCRIPTS/TELEMETRY/readme.txt @@ -0,0 +1,2 @@ +This directory is for Lua telemetry scripts. +Those scripts can be selected using DISPLAY screen in MODEL SETUP. diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/gover1.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/gover1.bmp new file mode 100755 index 0000000..e35f4cd Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/gover1.bmp differ diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/gover2.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/gover2.bmp new file mode 100755 index 0000000..75dd7f5 Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/gover2.bmp differ diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/splash1.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/splash1.bmp new file mode 100755 index 0000000..1f66160 Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/splash1.bmp differ diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/splash2.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/splash2.bmp new file mode 100755 index 0000000..f999535 Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/splash2.bmp differ diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/up1.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/up1.bmp new file mode 100755 index 0000000..2479a97 Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/up1.bmp differ diff --git a/SCRIPTS/TOOLS/BREAKOUT/gfx/up2.bmp b/SCRIPTS/TOOLS/BREAKOUT/gfx/up2.bmp new file mode 100755 index 0000000..7b71ea9 Binary files /dev/null and b/SCRIPTS/TOOLS/BREAKOUT/gfx/up2.bmp differ diff --git a/SCRIPTS/TOOLS/DSM FwdPrg_55_MIN.lua b/SCRIPTS/TOOLS/DSM FwdPrg_55_MIN.lua new file mode 100644 index 0000000..62aa215 --- /dev/null +++ b/SCRIPTS/TOOLS/DSM FwdPrg_55_MIN.lua @@ -0,0 +1,1046 @@ +local toolName = "TNS|DSM Frwd Prog v0.55a (MIN)|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 VERSION = "v0.55a-MIN" +local LANGUAGE = "en" +local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" + +local LOG_FILE = "/LOGS/dsm_min_log.txt" +local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt" +local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt" +local MSG_MIN_FILE_OFFSET = 20000 + +-- Phase +local PH_INIT = 0 +local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5 +local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8 +local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11 + +-- Line Types +local LT_MENU = 0x1C +local LT_LIST_NC, LT_LIST_NC2, LT_LIST, LT_LIST_ORI, LT_LIST_TOG = 0x6C, 0x6D, 0x0C, 0xCC, 0x4C +local LT_VALUE_NC = 0x60 +local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0 + +local Phase = PH_INIT +local SendDataToRX = 1 -- Initiate Sending Data + +local Text = {} +local List_Text = {} +local List_Text_Img = {} +local Flight_Mode = "Flight Mode" +local RxName = {} + +local TXInactivityTime = 0 +local RXInactivityTime = 0 +local TX_Info_Step = 0 +local TX_Info_Type = 0 +local Change_Step = 0 +local originalValue = 0 + +local TX_MAX_CH = 12 - 6 -- Number of Channels after Ch6 + +--local ctx = { +local ctx_SelLine = 0 -- Current Selected Line +local ctx_EditLine = nil -- Current Editing Line +local ctx_CurLine = -1 -- Current Line Requested/Parsed via h message protocol +local ctx_isReset = false -- false when starting from scracts, true when starting from Reset +--} + +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + modelOutputChannel = {}, -- Output information from OTX/ETX + AirWingTailDesc = "", + + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script +} + +local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 } +local MenuLines = {} +local RX = { Name = "", Version = "" } + +local logFile = nil + +--local LCD_X_LINE_TITLE = 0 +--local LCD_X_LINE_VALUE = 75 + +local LCD_W_BUTTONS = 19 +local LCD_H_BUTTONS = 10 + +local LCD_X_MAX = 128 +local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1 + +local LCD_Y_LINE_HEIGHT = 7 +local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + +local TEXT_ATTR = SMLSIZE + +local function LOG_open() + logFile = io.open(LOG_FILE, "w") -- Truncate Log File +end + +local function LOG_write(...) + if (logFile == nil) then LOG_open() end + local str = string.format(...) + io.write(logFile, str) +end + +local function LOG_close() + if (logFile ~= nil) then io.close(logFile) end +end + +----- Line Type +local function isIncrementalValueUpdate(line) + if (line.Type == LT_LIST_NC or line.Type == LT_LIST_NC2 or + line.Type == LT_VALUE_NC or line.Type == LT_VALUE_DEGREES) then return false end + return true +end + +local function isSelectable(line) + if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude + if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page + if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line + if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode + return false; +end + +local function isListLine(line) + return line.Type==LT_LIST_NC or line.Type==LT_LIST_NC2 or + line.Type == LT_LIST or line.Type == LT_LIST_ORI or line.Type == LT_LIST_TOG +end + +local function isEditing() + return ctx_EditLine ~= nil +end + + +---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- + +local function int16_LSB(number) -- Less Significat byte + local r, x = bit32.band(number, 0xFF) + return r +end + +local function int16_MSB(number) -- Most signifcant byte + return bit32.rshift(number, 8) +end + +local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value + return bit32.lshift(msb, 8) + lsb +end + +local function Dsm_to_SInt16(lsb, msb) -- Componse a SIGNED Int16 value + local value = bit32.lshift(msb, 8) + lsb + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value + if value < 0 then + value = 0x10000 + value + end + return value +end + +----------------------- +local function rtrim(s) + local n = string.len(s) + while n > 0 and string.find(s, "^%s", n) do n = n - 1 end + return string.sub(s, 1, n) +end + +local function GetTextInfoFromFile(pos) + local f=MSG_FILE + if (pos >= MSG_MIN_FILE_OFFSET) then -- Depending on offset, use the main, or MIN version + f = MSG_FILE_MIN + pos = pos - MSG_MIN_FILE_OFFSET + end + + -- open and read File + local dataFile = io.open(f, "r") + io.seek(dataFile,pos) + local buff = io.read(dataFile, 100) + io.close(dataFile) + + local line="" + local index="" + local type="" + + local pipe=0 + local comment=0 + local newPos = pos + + -- Parse the line: + -- Format: TT|0x999|Text -- Comment + for i=1,#buff do + newPos=newPos+1 + local ch = string.sub(buff,i,i) + + if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....) + elseif (ch=="/") then pipe=6 -- far right end, like comment + elseif (ch=="\r") then -- Ignore CR + elseif (ch=="\n") then break -- LF, end of line + elseif (ch=="-") then -- March comments + comment=comment+1 + if (comment==2) then pipe=6 end -- Comment part of line + else + -- regular char + comment=0 + if (pipe==0) then type=type..ch -- in TT (Type) + elseif (pipe==1) then index=index..ch -- in Index + elseif (pipe<6) then line=line..ch end -- in Text + end -- Regular char + end -- Fpr + + return type, index, rtrim(line), newPos +end + +local function GetTextFromFile(pos) + if (pos==nil) then return nil end + local t,i,l, p = GetTextInfoFromFile(pos) + return l +end + +----------------------- +local function Get_Text(index) + local pos = Text[index] + local out = "" + + if (pos == nil) then + out = string.format("Unknown_%X", index) + else + out = GetTextFromFile(pos) + end + + --local out = Text[index] or string.format("Unknown_%X", index) + if (index >= 0x8000) then + out = Flight_Mode + end + return out +end + +local function Get_Text_Value(index) + local pos = List_Text[index] + local out = "" + + if (pos == nil) then + out = Get_Text(index) + else + out = GetTextFromFile(pos) + end + + --local out = List_Text[index] or Get_Text(index) + return out +end +--------------------- +local function Get_RxName(index) + local out = RxName[index] or string.format("Unknown_%X", index) + return out +end +-------------------- + +local function DSM_Connect() + --Init TX buffer + multiBuffer(3, 0x00) + --Init RX buffer + multiBuffer(10, 0x00) + --Init telemetry + multiBuffer(0, string.byte('D')) + multiBuffer(1, string.byte('S')) + multiBuffer(2, string.byte('M')) +end + +local function DSM_Release() + multiBuffer(0, 0) +end +-------------------- +local function DSM_Send(...) + local arg = { ... } + for i = 1, #arg do + multiBuffer(3 + i, arg[i]) + end + multiBuffer(3, 0x70 + #arg) +end +--------------------- + +function ChangePhase(newPhase) + Phase = newPhase + SendDataToRX = 1 +end + +local function Value_Add(dir) + local line = MenuLines[ctx_SelLine] + local origVal = line.Val + local inc = dir + + if (not isListLine(line)) then -- List do slow inc + local Speed = getRotEncSpeed() + if Speed == ROTENC_MIDSPEED then + inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then + inc = (15 * dir) + end + end + + line.Val = line.Val + inc + + if line.Val > line.Max then + line.Val = line.Max + elseif line.Val < line.Min then + line.Val = line.Min + end + + if (origVal~=line.Val and isIncrementalValueUpdate(line)) then + -- Update RX value on every change, otherwise, just at the end + ChangePhase(PH_VAL_CHANGING) + end +end +-------------- + +local function GotoMenu(menuId, lastSelectedLine) + Menu.MenuId = menuId + ctx_SelLine = lastSelectedLine + -- Request to load the menu Again + ChangePhase(PH_TITLE) +end + +local function DSM_HandleEvent(event) + if event == EVT_VIRTUAL_EXIT then + if Phase == PH_RX_VER then + Phase = PH_EXIT_DONE -- Exit program + else + if isEditing() then -- Editing a Line, need to restore original value + MenuLines[ctx_EditLine].Val = originalValue + event = EVT_VIRTUAL_ENTER + else + if (Menu.BackId > 0 ) then -- Back?? + ctx_SelLine = -1 --Back Button + event = EVT_VIRTUAL_ENTER + else + ChangePhase(PH_EXIT_REQ) + end + end + end + end -- Exit + + if Phase == PH_RX_VER then return end -- nothing else to do + + if event == EVT_VIRTUAL_NEXT then + if isEditing() then -- Editting? + Value_Add(1) + else + if ctx_SelLine < 7 then -- On a regular line + local num = ctx_SelLine -- Find the prev selectable + for i = ctx_SelLine + 1, 6, 1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + return + end + + if event == EVT_VIRTUAL_PREV then + if isEditing() then -- In Edit Mode + Value_Add(-1) + else + if ctx_SelLine == 8 and Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif ctx_SelLine > 0 then + if ctx_SelLine > 6 then + ctx_SelLine = 7 --NEXT + end + local num = ctx_SelLine -- Find Prev Selectable line + for i = ctx_SelLine - 1, 0, -1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if (Menu.BackId > 0) then + ctx_SelLine = -1 -- Back + end + end + else + ctx_SelLine = -1 -- Back + end + end + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + if isEditing() then + MenuLines[ctx_SelLine].Val = MenuLines[ctx_SelLine].Def + ChangePhase(PH_VAL_CHANGING) + end + elseif event == EVT_VIRTUAL_ENTER then + if ctx_SelLine == -1 then -- Back + GotoMenu(Menu.BackId, 0x80) + elseif ctx_SelLine == 7 then -- Next + GotoMenu(Menu.NextId, 0x82) + elseif ctx_SelLine == 8 then -- Prev + GotoMenu(Menu.PrevId, 0x81) + elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then + GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu + else + -- value entry + if isEditing() then + ctx_EditLine = nil -- Done Editting + ChangePhase(PH_VAL_EDIT_END) + else -- Start Editing + ctx_EditLine = ctx_SelLine + originalValue = MenuLines[ctx_SelLine].Val + ChangePhase(PH_VAL_EDITING) + end + end + end +end +------------------------------------------------------------------------------------------------------------ + +local function SendTxInfo(portNo) + -- TxInfo_Type=0 : AR636 Main Menu (Send port/Channel info + SubTrim + Travel) + -- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20) + -- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown) + + + if (TX_Info_Step == 0) then + -- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F) + local info = MODEL.DSM_ChannelInfo[portNo] + DSM_Send(0x20, 0x06, portNo, portNo, info[0],info[1]) + LOG_write("TX:DSM_TxInfo_20(Port=#%d, Port Use)\n", portNo) + + if (TX_Info_Type == 0x1F) then -- SmartRx + TX_Info_Step = 1 + elseif (TX_Info_Type == 0x00) then -- AR636 + TX_Info_Step = 2 + end + elseif (TX_Info_Step == 1) then + local info = MODEL.modelOutputChannel[portNo] + local leftTravel = math.abs(math.floor(info.min/10)) + local rightTravel = math.abs(math.floor(info.max/10)) + + DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) + LOG_write("TX:DSM_TxInfo_Travel(Port=#%d,(L=%d - R=%d))\n", portNo,leftTravel,rightTravel) + + TX_Info_Step = 2 + elseif (TX_Info_Step == 2) then + -- Subtrim + local b1,b2,b3,b4 = 0x00, 0x8E, 0x07, 0x72 -- (192-1904) + if (portNo==0) then -- Thr + b1,b2,b3,b4 = 0x00, 0x00, 0x07, 0xFF -- (0-2047) + end + + DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. + LOG_write("TX:DSM_TxInfo_SubTrim(Port=#%d)\n", portNo) + + if (TX_Info_Type == 0x00) then -- AR636 + TX_Info_Step = 5 -- End Step + else + TX_Info_Step = 3 + end + elseif (TX_Info_Step == 3) then + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) + DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown + TX_Info_Step = 4 + elseif (TX_Info_Step == 4) then + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) + DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown + TX_Info_Step = 5 + elseif (TX_Info_Step == 5) then + LOG_write("TX:DSM_TxInfo_END(Port=#%d)\n", portNo) + DSM_Send(0x22, 0x04, 0x00, 0x00) + TX_Info_Step = 0 -- Done!! + end + + if (TX_Info_Step > 0) then + SendDataToRX = 1 -- keep Transmitig + end +end + +local function DSM_SendUpdate(line) + local valId = line.ValId + local value = sInt16ToDsm(line.Val) + + LOG_write("TX:ChangeValue(VId=0x%04X,Val=%d)\n", valId, line.Val) + DSM_Send(0x18, 0x06, + int16_MSB(valId), int16_LSB(valId), + int16_MSB(value), int16_LSB(value)) -- send current values +end + +local function DSM_SendValidate(line) + local valId = line.ValId + LOG_write("TX:ValidateValue(VId=0x%04X)\n", valId) + DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) +end + +local function DSM_SendRequest() + --LOG_write("DSM_SendRequest Phase=%d\n",Phase) + -- Need to send a request + local menuId = Menu.MenuId + local menuLSB = int16_LSB(menuId) + local menuMSB = int16_MSB(menuId) + + if Phase == PH_RX_VER then -- request RX version + DSM_Send(0x11, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) + LOG_write("TX:GetVersion(TX_MAX_CH=%d)\n",TX_MAX_CH+6) + + elseif Phase == PH_WAIT_CMD then -- keep connection open + DSM_Send(0x00, 0x04, 0x00, 0x00) + LOG_write("TX:TxHb\n") + + elseif Phase == PH_TITLE then -- request menu title + if menuId == 0 then + -- very first menu only + DSM_Send(0x12, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) + else + -- Any other menu + DSM_Send(0x16, 0x06, menuMSB, menuLSB, 0x00, ctx_SelLine) + if (menuId == 0x0001) then -- Executed Save&Reset menu + Phase = PH_RX_VER + ctx_isReset = true + end + end + LOG_write("TX:GetMenu(M=0x%04X,L=%d)\n", menuId, ctx_SelLine) + + elseif Phase == PH_TX_INFO then -- TX Info + SendTxInfo(ctx_CurLine) + + elseif Phase == PH_LINES then -- request menu lines + if ctx_CurLine == -1 then + DSM_Send(0x13, 0x04, menuMSB, menuLSB) -- GetFirstLine + else + DSM_Send(0x14, 0x06, menuMSB, menuLSB, 0x00, ctx_CurLine) -- line X + end + LOG_write("TX:GetNextLine(LastLine=%d)\n", ctx_CurLine) + + elseif Phase == PH_VALUES then -- request menu values + local valId = MenuLines[ctx_CurLine].ValId + DSM_Send(0x15, 0x06, + menuMSB, menuLSB, + int16_MSB(valId), int16_LSB(valId)) + LOG_write("TX:GetNextValue(LastVId=0x%04X)\n", valId) + + elseif Phase == PH_VAL_EDITING then -- Editing a line (like a HB) + local line = MenuLines[ctx_SelLine] + DSM_Send(0x1A, 0x04, 0x00, ctx_SelLine) + LOG_write("TX:EditingValueLine(L=%d)\n", ctx_SelLine) + + elseif Phase == PH_VAL_CHANGING then -- change value during editing + local line = MenuLines[ctx_SelLine] + if (Change_Step==0) then + DSM_SendUpdate(line) + if line.Type == LT_LIST then -- Incremental Validation?? + Change_Step=1 + end + else -- Change_Step==1 + DSM_SendValidate(line) + Change_Step=0 + end + if (Change_Step==0) then Phase=PH_VAL_EDITING else SendDataToRX=1 end -- Done with change? + + elseif Phase == PH_VAL_EDIT_END then -- Done Editing line + local line = MenuLines[ctx_SelLine] + + if (Change_Step==0) then + DSM_SendUpdate(line) + Change_Step=1 + elseif (Change_Step==1) then + DSM_SendValidate(line) + Change_Step=2 + else -- Change_Step==3 + LOG_write("TX:EditValueEnd(L=%d)\n", ctx_SelLine) + DSM_Send(0x1B, 0x04, 0x00, ctx_SelLine) + Change_Step=0 + end + if (Change_Step==0) then Phase = PH_WAIT_CMD else SendDataToRX=1 end -- Done with change? + + elseif Phase == PH_EXIT_REQ then -- EXIT Request + DSM_Send(0x1F, 0x02, 0xAA) + LOG_write("TX:TX Exit Request\n") + end +end + +local function DSM_ProcessResponse() + local cmd = multiBuffer(11) + if cmd == 0x01 then -- read version + RX.Name = Get_RxName(multiBuffer(13)) + RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) + + Menu.MenuId = 0 + Phase = PH_TITLE + LOG_write("RX:Version: %s %s\n", RX.Name, RX.Version) + + elseif cmd == 0x02 then -- read menu title + local menu = Menu + + menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + menu.Text = Get_Text(menu.TextId) + menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21)) + + for i = 0, 6 do -- clear menu + MenuLines[i] = { MenuId = 0, Type = 0, TextId = 0, ValId = 0, Min = 0, Max = 0, Def = 0, Val = nil } + end + ctx_CurLine = -1 + ctx_SelLine = -1 -- highlight Back + + LOG_write("RX:Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text) + + if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? + Phase = PH_RX_VER + else + Phase = PH_LINES + end + + elseif cmd == 0x03 then -- read menu lines + local i = multiBuffer(14) + local type = multiBuffer(15) + local line = MenuLines[i] + + ctx_CurLine = i + + line.lineNum = i + line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + line.Type = type + line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + line.Text = Get_Text(line.TextId) + line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + + -- Signed int values + line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21)) + line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) + line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) + + if line.Type == LT_MENU then + -- nothing to do on menu entries + elseif isListLine(line) then + line.Val = nil --line.Def - line.Min -- use default value not sure if needed + line.Def = line.Min -- pointer to the start of the list in Text + line.Max = line.Max - line.Min -- max index + line.Min = 0 -- min index + else -- default to numerical value + line.Val = nil --line.Def -- use default value not sure if needed + if (line.Min == 0 and line.Max == 100) or (line.Min == -100 and line.Max == 100) or + (line.Min == 0 and line.Max == 150) or (line.Min == -150 and line.Max == 150) then + line.Type = LT_VALUE_PERCENT -- Override to Value Percent + end + end + + if ctx_SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu + ctx_SelLine = ctx_CurLine + end + + LOG_write("RX:Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text) + + if (line.MenuId~=Menu.MenuId) then -- Going Back too fast: Stil receiving lines from previous menu + Menu.MenuId = line.MenuId + end + + Phase = PH_LINES + + elseif cmd == 0x04 then -- read menu values + -- Identify the line and update the value + local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int + + local updatedLine = nil + for i = 0, 6 do -- Find the menu line for this value + local line = MenuLines[i] + if line.Type ~= 0 then + if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line + line.Val = value + ctx_CurLine = i + updatedLine = line + + local valueTxt = value + if isListLine(line) then + valueTxt = Get_Text_Value(line.Def + value) .. " [" .. value .. "]" + end + + LOG_write("RX: Value Updated: #%d VId=0x%04X Value=%s\n", i, valId, valueTxt) + break + end + end + end + + --if (updatedLine == nil) then + -- LOG_write("Cannot Find Line for ValueId=%x\n", valId) + --end + Phase = PH_VALUES + + elseif cmd == 0x05 then -- Request TX info + ctx_CurLine = multiBuffer(12) + TX_Info_Type = multiBuffer(13) + TX_Info_Step = 0 + Phase = PH_TX_INFO + LOG_write("RX:TXInfoReq: Port=%d T=0x%02X\n", ctx_CurLine, TX_Info_Type) + + elseif cmd == 0xA7 then -- RX EXIT Request + if Phase == PH_EXIT_REQ then -- Response to our EXIT req + Phase = PH_EXIT_DONE + else -- Unexpected RX Exit + DSM_Release() + error("RX Connection Drop") + end + + elseif cmd == 0x00 then -- RX Heartbeat + LOG_write("RX:RxHb\n") + end + + return cmd +end + + +local function DSM_Send_Receive() + + -- Receive part: Process incoming messages if there is nothing to send + if SendDataToRX==0 and multiBuffer(10) == 0x09 then + local cmd = DSM_ProcessResponse() + -- Data processed + multiBuffer(10, 0x00) + RXInactivityTime = getTime() + 800 -- Reset Inactivity timeout (8s) + + if (cmd > 0x00) then -- RX-HeartBeat?? + -- Only change to SEND mode if we received a valid response (Ignore heartbeat) + SendDataToRX = 1 + end + else + -- Check if enouth time has passed from last Received activity + if (getTime() > RXInactivityTime and Phase~=PH_RX_VER and Phase~= PH_EXIT_DONE) then + if (isEditing()) then -- If Editing, extend time + RXInactivityTime = getTime() + 400 + else + DSM_Release() + error("RX Disconnected") + end + end + end + + -- Sending part -- + if SendDataToRX == 1 then + SendDataToRX = 0 + DSM_SendRequest() + TXInactivityTime = getTime() + 200 -- Reset Inactivity timeout (2s) + else + -- Check if enouth time has passed from last transmit activity + if getTime() > TXInactivityTime then + SendDataToRX = 1 -- Switch to Send mode to send heartbeat + + -- Change to Idle/HB mode if we are wating for RX version + if Phase ~= PH_RX_VER then + -- Phase = If IsEditing then PH_VAL_EDITING else PH_WAIT_CMD + Phase = (isEditing() and PH_VAL_EDITING) or PH_WAIT_CMD + end + end + end +end + +----- + +local function showBitmap(x, y, imgDesc) + local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|' + local imgName, imgMsg = f(), f() + + f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':' + local p1, p2 = f(), f() + + lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG + lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG +end + + +local function drawButton(x, y, text, active) + local attr = TEXT_ATTR + if (active) then attr = attr + INVERS end + lcd.drawText(x, y, text, attr) +end + +local ver_rx_count = 0 + +local function DSM_Display() + lcd.clear() + --Draw RX Menu + if Phase == PH_RX_VER then + lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS) + + local msgId = 0x300 -- Waiting for RX + if (ctx_isReset) then msgId=0x301 end -- Waiting for Reset + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK) + return + end + + -- display Program version or RX version + local msg = RX.Name .. " v" .. RX.Version + if (ver_rx_count < 70) then + msg = RX.Name .. " v" .. RX.Version + ver_rx_count = ver_rx_count + 1 + else + msg = "FProg "..VERSION + ver_rx_count = ver_rx_count + 1 + if (ver_rx_count > 140) then ver_rx_count=0 end + end + lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) + + if Menu.MenuId == 0 then return end; -- No Title yet + + -- Got a Menu + lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS) + + if (Phase == PH_TX_INFO) then + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, "Sending CH"..(ctx_CurLine+1), TEXT_ATTR) + end + + local y = LCD_Y_LINE_HEIGHT + 2 + for i = 0, 6 do + local attrib = TEXT_ATTR + if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line + + local line = MenuLines[i] + + if line ~= nil and line.Type ~= 0 then + local heading = Get_Text(line.TextId) + + if (line.TextId >= 0x8000) then -- Flight mode + heading = " " .. Flight_Mode .. " " + if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end + else + local text = nil + if line.Type ~= LT_MENU then -- list/value + if line.Val ~= nil then + if isListLine(line) then + local textId = line.Val + line.Def + text = Get_Text_Value(textId) + + local offset = 0 + if (line.Type==LT_LIST_ORI) then offset = offset + 0x100 end --FH6250 hack + local imgDesc = GetTextFromFile(List_Text_Img[textId+offset]) + + if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value + showBitmap(1, 20, imgDesc) + end + else + text = line.Val + end + end -- if is Value + + if (ctx_EditLine == i) then -- Editing a Line + attrib = BLINK + INVERS + TEXT_ATTR + end + lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value + attrib = TEXT_ATTR + end + end -- not Flight mode + lcd.drawText(1, y, heading, attrib) -- display text + end + y = y + LCD_Y_LINE_HEIGHT + end -- for + + if Menu.BackId ~= 0 then + drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1) + end + + if Menu.NextId ~= 0 then + drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7) + end + + if Menu.PrevId ~= 0 then + drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8) + end +end + +----------------------------------------------------------------------------------------- + +local function load_msg_from_file(fileName, offset, FileState) + + if (FileState.state==nil) then -- Initial State + FileState.state=1 + FileState.lineNo=0 + FileState.filePos=0 + end + + if FileState.state==1 then + for l=1,10 do -- do 10 lines at a time + local type, sIndex, text + local lineStart = FileState.filePos + + type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos+offset) + + --print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos)) + + if (lineStart==FileState.filePos) then -- EOF + FileState.state=2 --EOF State + return 1 + end + FileState.lineNo = FileState.lineNo + 1 + + type = rtrim(type) + + if (string.len(type) > 0 and string.len(sIndex) > 0) then + local index = tonumber(sIndex) + local filePos = lineStart + offset + + if (index == nil) then + assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex)) + elseif (type == "T") then + Text[index] = filePos + elseif (type == "LT") then + List_Text[index] = filePos + elseif (type == "LI") then + List_Text_Img[index] = filePos + elseif (type == "FM") then + Flight_Mode = text + elseif (type == "RX") then + RxName[index] = text + else + assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type)) + end + end + end -- for + end -- if + + collectgarbage("collect") + return 0 +end + +local function DSM_Init_Model() + MODEL.DSM_ChannelInfo={} + MODEL.modelOutputChannel={} + + local ChInfo = MODEL.DSM_ChannelInfo + local OutCh = MODEL.modelOutputChannel + + for i=0, 11 do + ChInfo[i] = {[0]= 0x00, 0x00} + OutCh[i] = {min=1000, max=1000} + end + + ChInfo[0][1] = 0x40 -- Ch1 Thr (0x40) + ChInfo[1][1] = 0x01 -- Ch2 Ail (0x01) + ChInfo[2][1] = 0x02 -- Ch2 ElE (0x02) + ChInfo[3][1] = 0x04 -- Ch4 Rud (0x04) +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + LOG_open() + LOG_write("--- NEW SESSION\n") + + DSM_Init_Model() + collectgarbage("collect") + + --Set protocol to talk to + multiBuffer(0, string.byte('D')) + --test if value has been written + if multiBuffer(0) ~= string.byte('D') then + error("Not enough memory!") + return 2 + end + + if (LCD_W > 128) then + TEXT_ATTR = 0 + LCD_Y_LINE_HEIGHT = 25 + LCD_X_MAX = 300 + LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30 + + LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + end + + Phase = PH_INIT +end + + +----------------------------------------------------------------------------------------------------------- +local initStep=0 +local FileState = { lineNo=0} + +local function Inc_Init() + lcd.clear() + + if (initStep == 0) then + lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) + if (load_msg_from_file(MSG_FILE, 0, FileState)==1) then + initStep=1 + FileState = {} + collectgarbage("collect") + end + return 0 + elseif (initStep == 1) then + lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) + if (load_msg_from_file(MSG_FILE_MIN, MSG_MIN_FILE_OFFSET, FileState)==1) then + initStep=2 + FileState ={} + collectgarbage("collect") + end + return 0 + else -- initStep==2 + --initStep=3 + Phase = PH_RX_VER -- Done Init + DSM_Connect() + end +end + +------------------------------------------------------------------------------------------------------------ +-- Main + +local function DSM_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + if (Phase == PH_INIT) then + Inc_Init() -- Incremental initialization + return 0 + end + + DSM_Display() + DSM_HandleEvent(event) + DSM_Send_Receive() + collectgarbage("collect") + + if Phase == PH_EXIT_DONE then + DSM_Release() + LOG_close() + return 2 + else + return 0 + end +end + +return { init = DSM_Init, run = DSM_Run } diff --git a/SCRIPTS/TOOLS/DSM FwdPrg_56_Color.lua b/SCRIPTS/TOOLS/DSM FwdPrg_56_Color.lua new file mode 100644 index 0000000..b631963 --- /dev/null +++ b/SCRIPTS/TOOLS/DSM FwdPrg_56_Color.lua @@ -0,0 +1,790 @@ +local toolName = "TNS|DSM Forward Prog v0.56 (Color) |TNE" +local VERSION = "v0.56" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### +------------------------------------------------------------------------------ +-- This script library is a rewrite of the original DSM forward programming Lua +-- Script. The goal is to make it easier to understand, mantain, and to +-- separate the GUI from the DSM Forward programming engine/logic +-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc. + +-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module) +-- Rewrite/Enhancements By: Francisco Arzu +------------------------------------------------------------------------------ + +local SIMULATION_ON = true -- false: dont show simulation menu, TRUE: show simulation menu +local DEBUG_ON = 1 -- 0=NO DEBUG, 1=HIGH LEVEL 2=LOW LEVEL (Debug logged into the /LOGS/dsm.log) +local USE_SPECKTRUM_COLORS = true -- true: Use spectrum colors, false: use theme colors (default on OpenTX) +local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" +local IMAGE_PATH = DSMLIB_PATH .. "img/" + +local Log = assert(loadScript(DSMLIB_PATH.."DsmLogLib.lua"), "Not-Found: DSMLIB/DsmLogLib.lua")() +local menuLib = assert(loadScript(DSMLIB_PATH.."DsmMenuLib.lua"), "Not-Found: DSMLIB/DsmMenuLib.lua")(Log, DEBUG_ON) +local modelLib = assert(loadScript(DSMLIB_PATH.."DsmModelLib.lua"), "Not-Found: DSMLIB/DsmModelLib.lua")(Log, DEBUG_ON) +local menuProcessor = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua")(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON) + +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE +local DISP_ATTR = menuLib.DISP_ATTR +local DSM_Context = menuLib.DSM_Context + + +local lastRefresh=0 -- Last time the screen was refreshed +local REFRESH_GUI_MS = 300/10 -- 300ms.. Screen Refresh Rate.. to not waste CPU time (in 10ms units to be compatible with getTime()) +local originalValue = nil + +local touchButtonArea = {} +local EDIT_BUTTON = { DEFAULT=1001, DEC_10=1002, DEC_1=1003, INC_1=1004, INC_10=5, OK=1006, ESC=1007 } + +local IS_EDGETX = false -- DEFAULT until Init changed it + +local LCD_Y_MENU_TITLE = 20 +local LCD_W_MENU_TITLE = LCD_W-100 + +local LCD_X_LINE_MENU = 30 +local LCD_W_LINE_MENU = 350 + +local LCD_X_LINE_TITLE = 30 +local LCD_X_LINE_VALUE = 230 +local LCD_X_LINE_DEBUG = 390 + + +local LCD_Y_LINE_START = LCD_Y_MENU_TITLE + 30 +local LCD_Y_LINE_HEIGHT = 27 + +local LCD_Y_LOWER_BUTTONS = LCD_Y_LINE_START + 3 + (7 * LCD_Y_LINE_HEIGHT) + +-- TOOL BG COLOR +local LCD_TOOL_BGCOLOR = TEXT_BGCOLOR +-- TOOL HEADER +local LCD_TOOL_HDR_COLOR = MENU_TITLE_COLOR +local LCD_TOOL_HDR_BGCOLOR = TITLE_BGCOLOR +-- MENU HEADER +local LCD_MENU_COLOR = MENU_TITLE_COLOR +local LCD_MENU_BGCOLOR = MENU_TITLE_BGCOLOR +-- LINE SELECTED +local LCD_SELECTED_COLOR = TEXT_INVERTED_COLOR +local LCD_SELECTED_BGCOLOR = TEXT_INVERTED_BGCOLOR +local LCD_EDIT_BGCOLOR = MENU_TITLE_BGCOLOR -- WARNING_COLOR +-- NORMAL TEXT +local LCD_NORMAL_COLOR = TEXT_COLOR +local LCD_DISABLE_COLOR = TEXT_DISABLE_COLOR +local LCD_DEBUG_COLOR = LINE_COLOR +-- NORMAL BOX FRAME COLOR +local LCD_BOX_COLOR = TEXT_DISABLE_COLOR + + +local warningScreenON = true + + +--------------------- lcd.sizeText replacement ------------------------------------------------- +-- EdgeTx dont have lcd.sizeText, so we do an equivalent one using the string length and 5px per character +local function my_lcd_sizeText(s) + if (s==nil) then return 20 end + -- return: If IS_EDGETX then lcd.sizeText() else string.len() + return (IS_EDGETX and lcd.sizeText(s)) or (string.len(s)*10) +end + + +local function GUI_SwitchToRX() + -- Force to refresh DSM Info in MODEL (dsmLib pointing to the setup Script) + -- local dsmChannelInfo, description = modelLib.CreateDSMPortChannelInfo() + + menuProcessor.done() + Log.LOG_close() -- Reset the log + Log.LOG_open() + + menuProcessor = nil + collectgarbage("collect") + + modelLib.ReadTxModelData() + modelLib.ST_LoadFileData() + modelLib.CreateDSMPortChannelInfo() + + local dsmLib = assert(loadScript(DSMLIB_PATH.."DsmFwPrgLib.lua"),"Not-Found: DSMLIB/DsmFwPrgLib.lua") + menuProcessor = dsmLib(Log, menuLib, modelLib, DEBUG_ON) + + dsmLib = nil + collectgarbage("collect") + + menuProcessor.init(toolName) -- Initialize Library + DSM_Context.Refresh_Display = true +end + +local function GUI_SwitchToSIM() + menuProcessor.done() + Log.LOG_close() + + menuProcessor = nil + collectgarbage("collect") + + local simLib = assert(loadScript(DSMLIB_PATH.."DsmSimMenuLib.lua"), "Not-Found: DSMLIB/DsmSimMenuLib.lua") + menuProcessor = simLib(Log, menuLib, modelLib, DEBUG_ON) + + simLib = nil + collectgarbage("collect") + + menuProcessor.init(toolName) -- Initialize Library + DSM_Context.Refresh_Display = true +end + +local function GUI_SwitchToSetupMenu() + menuProcessor.done() + + menuProcessor = nil + collectgarbage("collect") + + local setupLib = assert(loadScript(DSMLIB_PATH.."DsmSetupMenuLib.lua"), "Not-Found: DSMLIB/DsmSetupMenuLib.lua") + menuProcessor = setupLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON) + + setupLib = nil + collectgarbage("collect") + + menuProcessor.init(toolName) -- Initialize Library + DSM_Context.Refresh_Display = true +end + +local function GUI_SwitchToMainMenu() + print("SWITCHING TO MAIN MENU") + menuProcessor.done() + + menuProcessor = nil + collectgarbage("collect") + + local mainMenuLib = assert(loadScript(DSMLIB_PATH.."DsmMainMenuLib.lua"), "Not-Found: DSMLIB/DsmMainMenuLib.lua") + menuProcessor = mainMenuLib(Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON) + + mainMenuLib = nil + collectgarbage("collect") + + menuProcessor.init(toolName) -- Initialize Library + DSM_Context.Refresh_Display = true +end + + +--------------------- Toucch Button Helpers ------------------------------------------------------------ +local function GUI_addTouchButton(x,y,w,h,line) + -- Add new button info to end of the array + touchButtonArea[#touchButtonArea+1] = {x=x, y=y, w=w, h=h, line=line} +end + +local function GUI_getTouchButton(x,y) + for i = 1, #touchButtonArea do + local button = touchButtonArea[i] + -- is the coordinate inside the button area?? + if (x >= button.x and x <= (button.x+button.w) and y >= button.y and (y <= button.y+button.h)) then + return button.line + end + end + return nil +end + +local function GUI_clearTouchButtons() + touchButtonArea = {} +end + +---------- Return Color to display Menu Lines ---------------------------------------------------------------- +local function GUI_GetTextColor(lineNum) + local ctx = DSM_Context + local txtColor = LCD_NORMAL_COLOR + -- Gray Out any other line except the one been edited + if (ctx.isEditing() and ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end + return txtColor +end + +local function GUI_GetFrameColor(lineNum) -- Frame Color for Value/Menu Boxes + local ctx = DSM_Context + local txtColor = LCD_BOX_COLOR + -- Gray Out any other line except the one been edited + if (ctx.EditLine~=lineNum) then txtColor=LCD_DISABLE_COLOR end + return txtColor +end + +-------------------------------------------------------------------------------------------------------- +-- Display Text inside a Rectangle. Inv: true means solid rectangle, false=only perimeter +local function GUI_Display_Boxed_Text(lineNum,x,y,w,h,text,inv, isNumber) + local ctx = DSM_Context + local txtColor = GUI_GetTextColor(lineNum) + local frameColor = GUI_GetFrameColor(lineNum) + -- If editing this lineNum, chose EDIT Color, else SELECTED Color + local selectedBGColor = (ctx.EditLine==lineNum and LCD_EDIT_BGCOLOR) or LCD_SELECTED_BGCOLOR + + if (inv) then + txtColor = LCD_SELECTED_COLOR + lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor) + else + lcd.drawRectangle(x-5, y-2, w, h, frameColor) + end + if (isNumber) then + lcd.drawNumber(x+w-10 , y, text, txtColor + RIGHT) + else + lcd.drawText(x , y, text, txtColor) + end +end + +------ Display Pre/Next/Back buttons +local function GUI_Diplay_Button(x,y,w,h,text,selected) + GUI_Display_Boxed_Text(-1,x,y,w,h,text,selected, false) +end + +------ Display MENU type of lines (Navigation, SubHeaders, and plain text comments) +local function GUI_Display_Line_Menu(lineNum,line,selected) + -- Menu Lines can be navidation to other Menus (if Selectable) + -- Or SubHeaders or Messages + + local txtColor = GUI_GetTextColor(lineNum) + local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_MENU + + if menuLib.isSelectableLine(line) then -- Draw Selectable Menus in Boxes + GUI_Display_Boxed_Text(lineNum,x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT, line.Text,selected, false) + GUI_addTouchButton(x, y, LCD_W_LINE_MENU, LCD_Y_LINE_HEIGHT,lineNum) + else + -- Non Selectable Menu Lines, plain text + -- Can be use for sub headers or just regular text lines (like warnings) + + local bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0 + + if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align??? + local tw = my_lcd_sizeText(line.Text)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Center?? + local tw = my_lcd_sizeText(line.Text) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_MENU)/2 - tw/2 -- Center - 1/2 Text + end + + lcd.drawText(x, y, line.Text, txtColor + bold) + end +end + +------ Display NAME : VALUES type of lines +local function GUI_Display_Line_Value(lineNum, line, value, selected, editing) + -- This Displays Name and Value Pairs + local txtColor = GUI_GetTextColor(lineNum) + local bold = 0 + local y = LCD_Y_LINE_START+(LCD_Y_LINE_HEIGHT*lineNum) + local x = LCD_X_LINE_TITLE + + ---------- NAME Part + local header = line.Text + -- ONLY do this for Flight Mode (Right Align or Centered) + if (menuLib.isFlightModeLine(line)) then + -- Display Header + Value together + header = menuLib.GetFlightModeValue(line) + + -- Bold Text??? + bold = (menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._BOLD) and BOLD) or 0 + + if menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._RIGHT) then -- Right Align + local tw = my_lcd_sizeText(header)+4 + x = LCD_X_LINE_VALUE - tw -- Right + elseif menuLib.isDisplayAttr(line.TextAttr,DISP_ATTR._CENTER) then -- Centered + local tw = my_lcd_sizeText(header) + x = x + (LCD_X_LINE_VALUE - LCD_X_LINE_TITLE)/2 - tw/2 -- Center - 1/2 Text + end + else + -- No Flight Mode, no effects here + header = header .. ":" + end + + lcd.drawText(x, y, header, txtColor + bold) -- display Line Header + + + --------- VALUE PART, Skip for Flight Mode since already show the value + if (value==nil) then return end + + if not menuLib.isFlightModeLine(line) then + if menuLib.isSelectableLine(line) then + --if (editing) then -- Any Special color/effect when editing?? + -- value = "["..value .. "]" + --end + -- Can select/edit value, Box it + local tw = math.max(my_lcd_sizeText(value)+10,45) -- Width of the Text in the lcd + GUI_Display_Boxed_Text(lineNum,LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,value,selected, not menuLib.isListLine(line)) + GUI_addTouchButton(LCD_X_LINE_VALUE,y,tw,LCD_Y_LINE_HEIGHT,lineNum) + + lcd.drawText(LCD_X_LINE_VALUE+tw+5, y, (line.Format or ""), txtColor + bold) + else -- Not Editable, Plain Text + lcd.drawText(LCD_X_LINE_VALUE, y, value, txtColor) + end + end + +end + +local function GUI_Display_Menu(menu) + local ctx = DSM_Context + local w= LCD_W_MENU_TITLE + + -- Center Header + local tw = my_lcd_sizeText(menu.Text) + local x = w/2 - tw/2 -- Center of Screen - Center of Text + + lcd.drawFilledRectangle(0, LCD_Y_MENU_TITLE-2, w, LCD_Y_LINE_HEIGHT-2, LCD_MENU_BGCOLOR) + lcd.drawText(x,LCD_Y_MENU_TITLE,menu.Text, LCD_MENU_COLOR + BOLD) + + -- Back Button + if menu.BackId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,"Back",ctx.SelLine == menuLib.BACK_BUTTON) + GUI_addTouchButton(437-5,LCD_Y_MENU_TITLE+3,47,LCD_Y_LINE_HEIGHT,menuLib.BACK_BUTTON) + end + -- Next Button + if menu.NextId ~= 0 then + GUI_Diplay_Button(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Next",ctx.SelLine == menuLib.NEXT_BUTTON) + GUI_addTouchButton(437-5,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.NEXT_BUTTON) + end + -- Prev Button + if menu.PrevId ~= 0 then + GUI_Diplay_Button(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,"Prev",ctx.SelLine == menuLib.PREV_BUTTON) + GUI_addTouchButton(10,LCD_Y_LOWER_BUTTONS,47,LCD_Y_LINE_HEIGHT,menuLib.PREV_BUTTON) + end +end + +------------------------------------------------------------------------------------------------------------ +-- Display the EDIT mode buttons when editing a value + +local function GUI_Display_Edit_Buttons(line) + GUI_clearTouchButtons() -- Only this buttons can be touched + local x = 15 -- Inittial X position + local w = 55 -- Width of the buttons + + local showPrev = line.Val > line.Min + local showNext = line.Val < line.Max + + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,"ESC",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.ESC) + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," Def",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEFAULT) + + x=x+w+10 + if (not menuLib.isListLine(line)) then + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," << ",showPrev) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_10) + end + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," <",showPrev) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.DEC_1) + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >",showNext) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_1) + + x=x+w+10 + if (not menuLib.isListLine(line)) then + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," >>",showNext) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.INC_10) + end + + x=x+w+10 + GUI_Diplay_Button(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT," OK",true) + GUI_addTouchButton(x,LCD_Y_LOWER_BUTTONS,w,LCD_Y_LINE_HEIGHT,EDIT_BUTTON.OK) + +end + +local function GUI_ShowBitmap(x,y,imgData) + -- imgData format "bitmap.png|alt message" + local f = string.gmatch(imgData, '([^%|]+)') -- Iterator over values split by '|' + local imgName, imgMsg = f(), f() + + lcd.drawText(x, y, imgMsg or "") -- Alternate Image MSG + + local imgPath = IMAGE_PATH .. (imgName or "") + local bitmap = Bitmap.open(imgPath) + if (bitmap~=nil) then + lcd.drawBitmap(bitmap, x,y+20) + end +end + +------------------------------------------------------------------------------------------------------------ +local function GUI_Display() + local ctx = DSM_Context + lcd.clear(LCD_TOOL_BGCOLOR) + GUI_clearTouchButtons() + + if LCD_W ~= 480 then + -- Different Resolution.. Maybe just adjusting some of the constants will work, adjust it in DSM_Init?? + -- LCD_X_LINE_TITLE, LCD_Y_LINE_START, etc + lcd.drawText(LCD_X_LINE_TITLE,100,"Only supported in Color Radios of 480 resolution", BLINK) + return + end + + local header = "DSM Forward Programming "..VERSION.." " + if ctx.Phase ~= PHASE.RX_VERSION then + header = header .. ctx.RX.Name.." v"..ctx.RX.Version + end + + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR) + lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE) + + -- Getting RX Version + if ctx.Phase == PHASE.RX_VERSION then + if (ctx.isReset) then + lcd.drawText(LCD_X_LINE_TITLE,100, menuLib.Get_Text(0x301), BLINK) -- Resetting... + else + lcd.drawText(LCD_X_LINE_TITLE,100,menuLib.Get_Text(0x300), BLINK) -- Not valid RX + end + return + end + + + local menu = ctx.Menu + if menu.Text == nil then return end + + ----- Draw RX Menu --------- + GUI_Display_Menu(menu) + + -- Sending TX Information??? + if (ctx.Phase==PHASE.MENU_REQ_TX_INFO) then + --lcd.drawFilledRectangle(x-5, y-2, w, h, selectedBGColor) + --lcd.drawRectangle(x-5, y-2, w, h, frameColor) + lcd.drawText(LCD_X_LINE_TITLE,100, "Sending CH"..(ctx.CurLine+1)) -- Channel Info + return + end + + for i = 0, menuLib.MAX_MENU_LINES do + local line = ctx.MenuLines[i] + + if line ~= nil and line.Type ~= 0 then + if line.Type == LINE_TYPE.MENU then + GUI_Display_Line_Menu(i, line, i == ctx.SelLine) + else + local value = nil + if line.Val ~= nil then + value = line.Val + if menuLib.isListLine(line) then -- for Lists of Strings, get the text + value = menuLib.Get_List_Text(line.Val + line.TextStart) -- TextStart is the initial offset for text + -- Complentary IMAGE for this value to Display?? + local offset = 0 + if (line.Type==LINE_TYPE.LIST_MENU_ORI) then offset = offset + 0x100 end --FH6250 hack + + local imgData = menuLib.Get_List_Text_Img(line.Val + line.TextStart + offset) + + if (imgData and i == ctx.SelLine) then -- Optional Image and Msg for selected value + GUI_ShowBitmap(LCD_X_LINE_TITLE,LCD_Y_LINE_START, imgData) + end + end + end -- if Line[i]~=nil + GUI_Display_Line_Value(i, line, value, i == ctx.SelLine, i == ctx.EditLine) + end + end -- if ~MENU + end -- for + + if IS_EDGETX and ctx.isEditing() then + -- Display Touch button for Editing values + GUI_Display_Edit_Buttons(ctx.MenuLines[ctx.EditLine]) + end +end + +------------------------------------------------------------------------------------------------------------- +local function GUI_RotEncVal(line, dir) -- return encoder speed to inc or dec values + + if menuLib.isListLine(line) then return dir end + + local inc = 0 + local Speed = getRotEncSpeed() + + if Speed == ROTENC_MIDSPEED then inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then inc = (15 * dir) + else inc = dir end + + return inc +end + +------------------------------------------------------------------------------------ +-- Translate Tap/Touch of EDIT buttons to equivalent Key events +local function GUI_Translate_Edit_Buttons(button) + local event = EVT_TOUCH_TAP + local editInc = nil + + if (button==EDIT_BUTTON.ESC) then -- ESC + event = EVT_VIRTUAL_EXIT + elseif (button==EDIT_BUTTON.DEFAULT) then -- Default + event = EVT_VIRTUAL_ENTER_LONG + elseif (button==EDIT_BUTTON.DEC_10) then -- -10 + event = EVT_VIRTUAL_PREV + editInc = -10 + elseif (button==EDIT_BUTTON.DEC_1) then -- -1 + event = EVT_VIRTUAL_PREV + editInc = -1 + elseif (button==EDIT_BUTTON.INC_1) then -- +1 + event = EVT_VIRTUAL_NEXT + editInc = 1 + elseif (button==EDIT_BUTTON.INC_10) then -- + 10 + event = EVT_VIRTUAL_NEXT + editInc = 10 + elseif (button==EDIT_BUTTON.OK) then -- OK + event = EVT_VIRTUAL_ENTER + else + + end + + return event, editInc +end + +------------------------------------------------------------------------------------------------------------ +-- Handle Events comming from the GUI +local function GUI_HandleEvent(event, touchState) + local ctx = DSM_Context + local menu = ctx.Menu + local menuLines = ctx.MenuLines + local editInc = nil + + if (IS_EDGETX) then + if (event == EVT_TOUCH_TAP and ctx.isEditing()) then -- Touch and Editing + local button = GUI_getTouchButton(touchState.x, touchState.y) + if (button) then + event, editInc = GUI_Translate_Edit_Buttons(button) + end + end + + if (event == EVT_TOUCH_TAP or event == EVT_TOUCH_FIRST) and not ctx.isEditing() then -- Touch and NOT editing + if (DEBUG_ON) then Log.LOG_write("%s: EVT_TOUCH_TAP %d,%d\n",menuLib.phase2String(ctx.Phase),touchState.x, touchState.y) end + local button = GUI_getTouchButton(touchState.x, touchState.y) + if button then + -- Found a valid line + ctx.SelLine = button + ctx.Refresh_Display=true + if event == EVT_TOUCH_TAP then -- EVT_TOUCH_FIRST only move focus + event = EVT_VIRTUAL_ENTER + end + end + end + end -- IS_EDGETX + + if event == EVT_VIRTUAL_EXIT then + ctx.Refresh_Display=true + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_EXIT\n",menuLib.phase2String(ctx.Phase)) end + if ctx.Phase == PHASE.RX_VERSION then + menuLib.ChangePhase(PHASE.EXIT_DONE) -- Just Exit the Script + else + if ctx.isEditing() then -- Editing a Line, need to restore original value + local line = ctx.MenuLines[ctx.EditLine] + line.Val = originalValue + menuLib.Value_Write_Validate(line) + elseif (menu.BackId > 0 ) then -- Back?? + ctx.SelLine = menuLib.BACK_BUTTON + event = EVT_VIRTUAL_ENTER + else + menuLib.ChangePhase(PHASE.EXIT) + end + end + end + + if ctx.Phase == PHASE.RX_VERSION then return end + + if event == EVT_VIRTUAL_NEXT then + ctx.Refresh_Display=true + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_NEXT\n",menuLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editing a Line, need to inc the value + local line=ctx.MenuLines[ctx.EditLine] + menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, 1)) + else -- not editing, move selected line to NEXT + menuLib.MoveSelectionLine(1) + end + return + end + + if event == EVT_VIRTUAL_PREV then + ctx.Refresh_Display=true + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_PREV\n",menuLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then -- Editiing a line, need to dec the value + local line=ctx.MenuLines[ctx.EditLine] + menuLib.Value_Add(line, editInc or GUI_RotEncVal(line, -1)) + else -- not editing, move selected line to PREV + menuLib.MoveSelectionLine(-1) + end + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + ctx.Refresh_Display=true + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER_LONG\n",menuLib.phase2String(ctx.Phase)) end + if ctx.isEditing() then + -- reset the value to default + menuLib.Value_Default(menuLines[ctx.EditLine]) -- Update value in RX if needed + end + return + end + + if event == EVT_VIRTUAL_ENTER then + ctx.Refresh_Display=true + if (DEBUG_ON) then Log.LOG_write("%s: EVT_VIRTUAL_ENTER, SelLine=%d\n",menuLib.phase2String(ctx.Phase), ctx.SelLine) end + if ctx.SelLine == menuLib.BACK_BUTTON then -- Back + if (menu.BackId==0xFFF9) then + -- SPECIAL Main Menu + GUI_SwitchToMainMenu() + else + menuLib.GotoMenu(menu.BackId,0x80) + end + elseif ctx.SelLine == menuLib.NEXT_BUTTON then -- Next + menuLib.GotoMenu(menu.NextId,0x82) + elseif ctx.SelLine == menuLib.PREV_BUTTON then -- Prev + menuLib.GotoMenu(menu.PrevId,0x81) + elseif menuLines[ctx.SelLine].ValId ~= 0 then -- Menu or Value + + if menuLines[ctx.SelLine].Type == LINE_TYPE.MENU then -- Navigate to Menu + if (menuLines[ctx.SelLine].ValId==0xFFF1) then + -- SPECIAL Simulation menu to Simulator + GUI_SwitchToSIM() + elseif (menuLines[ctx.SelLine].ValId==0xFFF2) then + -- SPECIAL Simulation menu to go to RX + GUI_SwitchToRX() + elseif (menuLines[ctx.SelLine].ValId==0xFFF3) then + -- SPECIAL Settup Menu + GUI_SwitchToSetupMenu() + elseif (menuLines[ctx.SelLine].ValId==0xFFF9) then + -- SPECIAL Settup Menu + GUI_SwitchToMainMenu() + else + menuLib.GotoMenu(menuLines[ctx.SelLine].ValId, ctx.SelLine) -- ValId is the MenuId to navigate to + end + else -- Enter on a Value + if ctx.isEditing() then -- already editing a Line???? + menuLib.Value_Write_Validate(menuLines[ctx.SelLine]) + else -- Edit the current value + ctx.EditLine = ctx.SelLine + originalValue = menuLines[ctx.SelLine].Val + menuLib.ChangePhase(PHASE.VALUE_CHANGING_WAIT) + end + end + end + end +end + +local function init_colors() + -- osName in OpenTX is nil, otherwise is EDGETX + local ver, radio, maj, minor, rev, osname = getVersion() + if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil + + IS_EDGETX = string.sub(osname,1,1) == 'E' + + if (IS_EDGETX and USE_SPECKTRUM_COLORS) then + -- SPECKTRUM COLORS (only works on EDGETX) + LCD_TOOL_BGCOLOR = LIGHTWHITE + -- TOOL HEADER + LCD_TOOL_HDR_COLOR = WHITE + LCD_TOOL_HDR_BGCOLOR = DARKBLUE + -- MENU HEADER + LCD_MENU_COLOR = WHITE + LCD_MENU_BGCOLOR = DARKGREY + -- LINE SELECTED + LCD_SELECTED_COLOR = WHITE + LCD_SELECTED_BGCOLOR = ORANGE + LCD_EDIT_BGCOLOR = RED + -- NORMAL TEXT + LCD_NORMAL_COLOR = BLACK + LCD_DISABLE_COLOR = LIGHTGREY + LCD_DEBUG_COLOR = BLUE + -- NORMAL BOX FRAME COLOR + LCD_BOX_COLOR = LIGHTGREY + end +end + +local function GUI_Warning(event,touchState) + lcd.clear(LCD_TOOL_BGCOLOR) + local header = "DSM Forward Programming "..VERSION.." " + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 17, LCD_TOOL_HDR_BGCOLOR) + lcd.drawText(5, 0, header, LCD_TOOL_HDR_COLOR + SMLSIZE) + + lcd.drawText(100,20,"INFO", BOLD) + lcd.drawText(5,40,"DSM Forward programing shares TX Servo/Output settings", 0) + lcd.drawText(5,60,"with the RX. Make sure you setup your plane first in ", 0) + lcd.drawText(5,80,"the TX before your start Fwrd programming your RX.", 0) + lcd.drawText(5,100,"Wing & Tail type can be configured using this tool.", 0) + + lcd.drawText(5,150,"TX Gyro Servo settings are sent to the RX during 'Initial Setup'", 0) + lcd.drawText(5,170,"as well as when using RX 'Relearn Servo Settings'", 0) + lcd.drawText(5,200,"ALWAYS TEST Gyro reactions after this conditions before flying.", BOLD) + + lcd.drawText(100,250," OK ", INVERS + BOLD) + + if event == EVT_VIRTUAL_EXIT or event == EVT_VIRTUAL_ENTER or event == EVT_TOUCH_TAP then + warningScreenON = false + end + + return 0 +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + Log.LOG_open() + + init_colors() + modelLib.ReadTxModelData() + modelLib.ST_LoadFileData() + modelLib.CreateDSMPortChannelInfo() + + menuLib.Init() + menuProcessor.init() + return 0 +end + +------------------------------------------------------------------------------------------------------------ +-- Main +local function DSM_Run(event,touchState) + local ctx = DSM_Context + + if event == nil then + error("Cannot be run as a model script!") + Log.LOG_close() + return 2 + end + + if (warningScreenON) then + return GUI_Warning(event,touchState) + end + + GUI_HandleEvent(event,touchState) + + local ret = menuProcessor.run() -- Handle Send and Receive DSM Forward Programming Messages + + if ctx.Phase == PHASE.INIT then return 0 end + + + local refreshInterval = REFRESH_GUI_MS + + -- When using LCD BLINK attribute, we need faster refresh for BLINK to SHOW on LCD + if (ctx.Phase == PHASE.RX_VERSION or ctx.Phase==PHASE.MENU_REQ_TX_INFO) then -- Requesting RX Message Version usea BLINK? + ctx.Refresh_Display=true + refreshInterval = 20 -- 200ms + end + + if (not IS_EDGETX) then -- OPENTX NEEDS REFRESH ON EVERY CYCLE + GUI_Display() + -- Refresh display only if needed and no faster than 300ms, utilize more CPU to speedup DSM communications + elseif (ctx.Refresh_Display and (getTime()-lastRefresh) > refreshInterval) then --300ms from last refresh + GUI_Display() + ctx.Refresh_Display=false + lastRefresh=getTime() + end + + if ctx.Phase == PHASE.EXIT_DONE then + Log.LOG_close() + return 2 + else + return 0 + end +end + + +return { init=DSM_Init, run=DSM_Run } \ No newline at end of file diff --git a/SCRIPTS/TOOLS/DSM FwdPrg_56_MIN.lua b/SCRIPTS/TOOLS/DSM FwdPrg_56_MIN.lua new file mode 100644 index 0000000..9e99e70 --- /dev/null +++ b/SCRIPTS/TOOLS/DSM FwdPrg_56_MIN.lua @@ -0,0 +1,1088 @@ +local toolName = "TNS|DSM Frwd Prog v0.56 (MIN)|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 VERSION = "v0.56" +local LANGUAGE = "en" +local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" + +local LOG_FILE = "/LOGS/dsm_min_log.txt" +local MSG_FILE = DSMLIB_PATH.."msg_fwdp_" .. LANGUAGE .. ".txt" +local MSG_FILE_MIN = DSMLIB_PATH.."MIN_msg_fwdp_" .. LANGUAGE .. ".txt" +local MSG_MIN_FILE_OFFSET = 20000 + +-- Phase +local PH_INIT = 0 +local PH_RX_VER, PH_TITLE, PH_TX_INFO, PH_LINES, PH_VALUES = 1, 2, 3, 4, 5 +local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8 +local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11 + +-- Line Types +local LT_MENU = 0x1C +local LT_LIST_NC, LT_LIST_NC2, LT_LIST, LT_LIST_ORI, LT_LIST_TOG = 0x6C, 0x6D, 0x0C, 0xCC, 0x4C +local LT_VALUE_NC = 0x60 +local LT_VALUE_PERCENT, LT_VALUE_DEGREES = 0xC0, 0xE0 + +local Phase = PH_INIT +local SendDataToRX = 1 -- Initiate Sending Data + +local Text = {} +local List_Text = {} +local List_Text_Img = {} +local Flight_Mode = "Flight Mode" +local RxName = {} + +local TXInactivityTime = 0 +local RXInactivityTime = 0 +local TX_Info_Step = 0 +local TX_Info_Type = 0 +local Change_Step = 0 +local originalValue = 0 + +local TX_MAX_CH = 12 - 6 -- Number of Channels after Ch6 + +--local ctx = { +local ctx_SelLine = 0 -- Current Selected Line +local ctx_EditLine = nil -- Current Editing Line +local ctx_CurLine = -1 -- Current Line Requested/Parsed via h message protocol +local ctx_isReset = false -- false when starting from scracts, true when starting from Reset +--} + +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + modelOutputChannel = {}, -- Output information from OTX/ETX + + TX_CH_TEXT= { }, + PORT_TEXT = { }, + + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script +} + +local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 } +local MenuLines = {} +local RX_Name = "" +local RX_Version = "" + +local logFile = nil + +--local LCD_X_LINE_TITLE = 0 +--local LCD_X_LINE_VALUE = 75 + +local LCD_W_BUTTONS = 19 +local LCD_H_BUTTONS = 10 + +local LCD_X_MAX = 128 +local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1 + +local LCD_Y_LINE_HEIGHT = 7 +local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + +local TEXT_ATTR = SMLSIZE + +local function gc() + collectgarbage("collect") +end + +--[[ +local function gcTable(t) + if type(t)=="table" then + for i,v in pairs(t) do + if type(v) == "table" then + gcTable(v) + end + t[i] = nil + end + end + gc() + return t +end +--]] + +local function LOG_open() + logFile = io.open(LOG_FILE, "w") -- Truncate Log File +end + +local function LOG_write(...) + if (logFile == nil) then LOG_open() end + local str = string.format(...) + io.write(logFile, str) +end + +local function LOG_close() + if (logFile ~= nil) then io.close(logFile) end +end + +----- Line Type +local function isIncrementalValueUpdate(line) + if (line.Type == LT_LIST_NC or line.Type == LT_LIST_NC2 or + line.Type == LT_VALUE_NC or line.Type == LT_VALUE_DEGREES) then return false end + return true +end + +local function isSelectable(line) + if (line.TextId == 0x00CD) then return true end -- Exceptiom: Level model and capture attitude + if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page + if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line + if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode + return false; +end + +local function isListLine(line) + return line.Type==LT_LIST_NC or line.Type==LT_LIST_NC2 or + line.Type == LT_LIST or line.Type == LT_LIST_ORI or line.Type == LT_LIST_TOG +end + +local function isEditing() + return ctx_EditLine ~= nil +end + + +---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- + +local function int16_LSB(number) -- Less Significat byte + local r, x = bit32.band(number, 0xFF) + return r +end + +local function int16_MSB(number) -- Most signifcant byte + return bit32.rshift(number, 8) +end + +local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value + return bit32.lshift(msb, 8) + lsb +end + +local function Dsm_to_SInt16(lsb, msb) -- Componse a SIGNED Int16 value + local value = bit32.lshift(msb, 8) + lsb + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value + if value < 0 then + value = 0x10000 + value + end + return value +end + +----------------------- +local function rtrim(s) + local n = string.len(s) + while n > 0 and string.find(s, "^%s", n) do n = n - 1 end + return string.sub(s, 1, n) +end + +local function GetTextInfoFromFile(pos) + local f=MSG_FILE + if (pos >= MSG_MIN_FILE_OFFSET) then -- Depending on offset, use the main, or MIN version + f = MSG_FILE_MIN + pos = pos - MSG_MIN_FILE_OFFSET + end + + -- open and read File + local dataFile = io.open(f, "r") + io.seek(dataFile,pos) + local buff = io.read(dataFile, 100) + io.close(dataFile) + + local line="" + local index="" + local type="" + + local pipe=0 + local comment=0 + local newPos = pos + + -- Parse the line: + -- Format: TT|0x999|Text -- Comment + for i=1,#buff do + newPos=newPos+1 + local ch = string.sub(buff,i,i) + + if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....) + elseif (ch=="/") then pipe=6 -- far right end, like comment + elseif (ch=="\r") then -- Ignore CR + elseif (ch=="\n") then break -- LF, end of line + elseif (ch=="-") then -- March comments + comment=comment+1 + if (comment==2) then pipe=6 end -- Comment part of line + else + -- regular char + comment=0 + if (pipe==0) then type=type..ch -- in TT (Type) + elseif (pipe==1) then index=index..ch -- in Index + elseif (pipe<6) then line=line..ch end -- in Text + end -- Regular char + end -- Fpr + gc() + return type, index, rtrim(line), newPos +end + +local function GetTextFromFile(pos) + if (pos==nil) then return nil end + local t,i,l, p = GetTextInfoFromFile(pos) + return l +end + +local function getTxChText(index) + local ch = nil + local out = nil + + if (index >= 0x000D and index <= 0x000D+7) then ch = index - 0x000D + 5 -- ch5 + elseif (index >= 0x0036 and index <= 0x0036+11) then ch = index - 0x0036 end + + if (ch ~= nil) then + out = "Ch"..(ch+1) .. " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")" + --out = MODEL.PORT_TEXT[ch] or "--" + end + + return out +end + +----------------------- +local function Get_Text(index) + local pos = Text[index] + local out = nil + + if (pos == nil) then + out = string.format("Unknown_%X", index) + else + out = GetTextFromFile(pos) + end + + if (index >= 0x8000) then + out = Flight_Mode + end + return out +end + +local function Get_Text_Value(index) + local out = getTxChText(index) + if (out) then return out end + + local pos = List_Text[index] + if (pos == nil) then + out = Get_Text(index) + else + out = GetTextFromFile(pos) + end + + return out +end +--------------------- +local function Get_RxName(index) + local out = RxName[index] or string.format("Unknown_%X", index) + return out +end +-------------------- + +local function updateValText(line) + line.ValText = line.Val + if (isListLine(line)) then + line.ValText = Get_Text_Value(line.TextStart + line.Val) + end +end + +local function DSM_Connect() + --Init TX buffer + multiBuffer(3, 0x00) + --Init RX buffer + multiBuffer(10, 0x00) + --Init telemetry + multiBuffer(0, string.byte('D')) + multiBuffer(1, string.byte('S')) + multiBuffer(2, string.byte('M')) +end + +local function DSM_Release() + multiBuffer(0, 0) +end +-------------------- +local function DSM_Send(...) + local arg = { ... } + for i = 1, #arg do + multiBuffer(3 + i, arg[i]) + end + multiBuffer(3, 0x70 + #arg) +end +--------------------- + +function ChangePhase(newPhase) + Phase = newPhase + SendDataToRX = 1 +end + +local function Value_Add(dir) + local line = MenuLines[ctx_SelLine] + local origVal = line.Val + local inc = dir + + if (not isListLine(line)) then -- List do slow inc + local Speed = getRotEncSpeed() + if Speed == ROTENC_MIDSPEED then + inc = (5 * dir) + elseif Speed == ROTENC_HIGHSPEED then + inc = (15 * dir) + end + end + + line.Val = line.Val + inc + + if line.Val > line.Max then + line.Val = line.Max + elseif line.Val < line.Min then + line.Val = line.Min + end + + if (origVal~=line.Val) then -- Any changes? + if (isIncrementalValueUpdate(line)) then + -- Update RX value on every change, otherwise, just at the end + ChangePhase(PH_VAL_CHANGING) + end + updateValText(line) + end +end +-------------- + +local function GotoMenu(menuId, lastSelectedLine) + Menu.MenuId = menuId + ctx_SelLine = lastSelectedLine + -- Request to load the menu Again + ChangePhase(PH_TITLE) +end + +local function DSM_HandleEvent(event) + if event == EVT_VIRTUAL_EXIT then + if Phase == PH_RX_VER then + Phase = PH_EXIT_DONE -- Exit program + else + if isEditing() then -- Editing a Line, need to restore original value + MenuLines[ctx_EditLine].Val = originalValue + event = EVT_VIRTUAL_ENTER + else + if (Menu.BackId > 0 ) then -- Back?? + ctx_SelLine = -1 --Back Button + event = EVT_VIRTUAL_ENTER + else + ChangePhase(PH_EXIT_REQ) + end + end + end + end -- Exit + + if Phase == PH_RX_VER then return end -- nothing else to do + + if event == EVT_VIRTUAL_NEXT then + if isEditing() then -- Editting? + Value_Add(1) + else + if ctx_SelLine < 7 then -- On a regular line + local num = ctx_SelLine -- Find the prev selectable + for i = ctx_SelLine + 1, 6, 1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + return + end + + if event == EVT_VIRTUAL_PREV then + if isEditing() then -- In Edit Mode + Value_Add(-1) + else + if ctx_SelLine == 8 and Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif ctx_SelLine > 0 then + if ctx_SelLine > 6 then + ctx_SelLine = 7 --NEXT + end + local num = ctx_SelLine -- Find Prev Selectable line + for i = ctx_SelLine - 1, 0, -1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if (Menu.BackId > 0) then + ctx_SelLine = -1 -- Back + end + end + else + ctx_SelLine = -1 -- Back + end + end + return + end + + if event == EVT_VIRTUAL_ENTER_LONG then + if isEditing() then + MenuLines[ctx_SelLine].Val = MenuLines[ctx_SelLine].Def + ChangePhase(PH_VAL_CHANGING) + end + elseif event == EVT_VIRTUAL_ENTER then + if ctx_SelLine == -1 then -- Back + GotoMenu(Menu.BackId, 0x80) + elseif ctx_SelLine == 7 then -- Next + GotoMenu(Menu.NextId, 0x82) + elseif ctx_SelLine == 8 then -- Prev + GotoMenu(Menu.PrevId, 0x81) + elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then + GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu + else + -- value entry + if isEditing() then + ctx_EditLine = nil -- Done Editting + ChangePhase(PH_VAL_EDIT_END) + else -- Start Editing + ctx_EditLine = ctx_SelLine + originalValue = MenuLines[ctx_SelLine].Val + ChangePhase(PH_VAL_EDITING) + end + end + end +end +------------------------------------------------------------------------------------------------------------ + +local function SendTxInfo(portNo) + -- TxInfo_Type=0 : AR636 Main Menu (Send port/Channel info + SubTrim + Travel) + -- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20) + -- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown) + + + if (TX_Info_Step == 0) then + -- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F) + local info = MODEL.DSM_ChannelInfo[portNo] + local b0, b1, b2 = info[0], info[1], info[2] + DSM_Send(0x20, 0x06, portNo, portNo, b0,b1) + LOG_write("TX:DSM_TxInfo_20(Port=#%d, (%02x, %02x) %s)\n", portNo, b0,b1,b2 or "") + + if (TX_Info_Type == 0x1F) then -- SmartRx + TX_Info_Step = 1 + elseif (TX_Info_Type == 0x00) then -- AR636 + TX_Info_Step = 2 + end + elseif (TX_Info_Step == 1) then + local info = MODEL.modelOutputChannel[portNo] + local leftTravel = math.abs(math.floor(info.min/10)) + local rightTravel = math.abs(math.floor(info.max/10)) + + DSM_Send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) + LOG_write("TX:DSM_TxInfo_Travel(Port=#%d,(L=%d - R=%d))\n", portNo,leftTravel,rightTravel) + + TX_Info_Step = 2 + elseif (TX_Info_Step == 2) then + -- Subtrim + local b1,b2,b3,b4 = 0x00, 0x8E, 0x07, 0x72 -- (192-1904) + if (portNo==0) then -- Thr + b1,b2,b3,b4 = 0x00, 0x00, 0x07, 0xFF -- (0-2047) + end + + DSM_Send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. + LOG_write("TX:DSM_TxInfo_SubTrim(Port=#%d)\n", portNo) + + if (TX_Info_Type == 0x00) then -- AR636 + TX_Info_Step = 5 -- End Step + else + TX_Info_Step = 3 + end + elseif (TX_Info_Step == 3) then + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) + DSM_Send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown + TX_Info_Step = 4 + elseif (TX_Info_Step == 4) then + LOG_write("TX:DSM_TxInfo_24?(Port=#%d)\n", portNo) + DSM_Send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown + TX_Info_Step = 5 + elseif (TX_Info_Step == 5) then + LOG_write("TX:DSM_TxInfo_END(Port=#%d)\n", portNo) + DSM_Send(0x22, 0x04, 0x00, 0x00) + TX_Info_Step = 0 -- Done!! + end + + if (TX_Info_Step > 0) then + SendDataToRX = 1 -- keep Transmitig + end +end + +local function DSM_SendUpdate(line) + local valId = line.ValId + local value = sInt16ToDsm(line.Val) + + LOG_write("TX:ChangeValue(VId=0x%04X,Val=%d)\n", valId, line.Val) + DSM_Send(0x18, 0x06, + int16_MSB(valId), int16_LSB(valId), + int16_MSB(value), int16_LSB(value)) -- send current values +end + +local function DSM_SendValidate(line) + local valId = line.ValId + LOG_write("TX:ValidateValue(VId=0x%04X)\n", valId) + DSM_Send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) +end + +local function DSM_SendRequest() + --LOG_write("DSM_SendRequest Phase=%d\n",Phase) + -- Need to send a request + local menuId = Menu.MenuId + local menuLSB = int16_LSB(menuId) + local menuMSB = int16_MSB(menuId) + + if Phase == PH_RX_VER then -- request RX version + DSM_Send(0x11, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) + LOG_write("TX:GetVersion(TX_MAX_CH=%d)\n",TX_MAX_CH+6) + + elseif Phase == PH_WAIT_CMD then -- keep connection open + DSM_Send(0x00, 0x04, 0x00, 0x00) + --LOG_write("TX:TxHb\n") + + elseif Phase == PH_TITLE then -- request menu title + if menuId == 0 then + -- very first menu only + DSM_Send(0x12, 0x06, TX_MAX_CH, 0x14, 0x00, 0x00) + else + -- Any other menu + DSM_Send(0x16, 0x06, menuMSB, menuLSB, 0x00, ctx_SelLine) + if (menuId == 0x0001) then -- Executed Save&Reset menu + Phase = PH_RX_VER + ctx_isReset = true + end + end + LOG_write("TX:GetMenu(M=0x%04X,L=%d)\n", menuId, ctx_SelLine) + + elseif Phase == PH_TX_INFO then -- TX Info + SendTxInfo(ctx_CurLine) + + elseif Phase == PH_LINES then -- request menu lines + if ctx_CurLine == -1 then + DSM_Send(0x13, 0x04, menuMSB, menuLSB) -- GetFirstLine + else + DSM_Send(0x14, 0x06, menuMSB, menuLSB, 0x00, ctx_CurLine) -- line X + end + LOG_write("TX:GetNextLine(LastLine=%d)\n", ctx_CurLine) + + elseif Phase == PH_VALUES then -- request menu values + local valId = MenuLines[ctx_CurLine].ValId + DSM_Send(0x15, 0x06, + menuMSB, menuLSB, + int16_MSB(valId), int16_LSB(valId)) + LOG_write("TX:GetNextValue(LastVId=0x%04X)\n", valId) + + elseif Phase == PH_VAL_EDITING then -- Editing a line (like a HB) + local line = MenuLines[ctx_SelLine] + DSM_Send(0x1A, 0x04, 0x00, ctx_SelLine) + LOG_write("TX:EditingValueLine(L=%d)\n", ctx_SelLine) + + elseif Phase == PH_VAL_CHANGING then -- change value during editing + local line = MenuLines[ctx_SelLine] + if (Change_Step==0) then + DSM_SendUpdate(line) + if line.Type == LT_LIST then -- Incremental Validation?? + Change_Step=1 + end + else -- Change_Step==1 + DSM_SendValidate(line) + Change_Step=0 + end + if (Change_Step==0) then Phase=PH_VAL_EDITING else SendDataToRX=1 end -- Done with change? + + elseif Phase == PH_VAL_EDIT_END then -- Done Editing line + local line = MenuLines[ctx_SelLine] + + if (Change_Step==0) then + DSM_SendUpdate(line) + Change_Step=1 + elseif (Change_Step==1) then + DSM_SendValidate(line) + Change_Step=2 + else -- Change_Step==3 + LOG_write("TX:EditValueEnd(L=%d)\n", ctx_SelLine) + DSM_Send(0x1B, 0x04, 0x00, ctx_SelLine) + Change_Step=0 + end + if (Change_Step==0) then Phase = PH_WAIT_CMD else SendDataToRX=1 end -- Done with change? + + elseif Phase == PH_EXIT_REQ then -- EXIT Request + DSM_Send(0x1F, 0x02, 0xAA) + LOG_write("TX:TX Exit Request\n") + end +end + +local function DSM_ProcessResponse() + local cmd = multiBuffer(11) + if cmd == 0x01 then -- read version + RX_Name = Get_RxName(multiBuffer(13)) + RX_Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) + + Menu.MenuId = 0 + Phase = PH_TITLE + LOG_write("RX:Version: %s %s\n", RX_Name, RX_Version) + + elseif cmd == 0x02 then -- read menu title + local menu = Menu + + menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + menu.Text = Get_Text(menu.TextId) + menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21)) + + for i = 0, 6 do -- clear menu + MenuLines[i] = { Type = 0 } + end + ctx_CurLine = -1 + ctx_SelLine = -1 -- highlight Back + + LOG_write("RX:Menu: Mid=0x%04X \"%s\"\n", menu.MenuId, menu.Text) + + if (menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? + Phase = PH_RX_VER + else + Phase = PH_LINES + end + + elseif cmd == 0x03 then -- read menu lines + local i = multiBuffer(14) + local type = multiBuffer(15) + local line = MenuLines[i] + + ctx_CurLine = i + + line.lineNum = i + line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + line.Type = type + line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + line.Text = Get_Text(line.TextId) + line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + + -- Signed int values + line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21)) + line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) + line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) + + if line.Type == LT_MENU then + -- nothing to do on menu entries + elseif isListLine(line) then + line.Val = nil + line.TextStart = line.Min + line.Def = line.Def - line.Min -- normalize default value + line.Max = line.Max - line.Min -- normalize max index + line.Min = 0 -- min index + else -- default to numerical value + line.Val = nil --line.Def -- use default value not sure if needed + if (line.Min == 0 and line.Max == 100) or (line.Min == -100 and line.Max == 100) or + (line.Min == 0 and line.Max == 150) or (line.Min == -150 and line.Max == 150) then + line.Type = LT_VALUE_PERCENT -- Override to Value Percent + end + end + + if ctx_SelLine == -1 and isSelectable(line) then -- Auto select first selectable line of the menu + ctx_SelLine = ctx_CurLine + end + + LOG_write("RX:Line: #%d Vid=0x%04X T=0x%02X \"%s\"\n", i, line.ValId, type, line.Text) + + if (line.MenuId~=Menu.MenuId) then -- Going Back too fast: Stil receiving lines from previous menu + Menu.MenuId = line.MenuId + end + + Phase = PH_LINES + + elseif cmd == 0x04 then -- read menu values + -- Identify the line and update the value + local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int + + --local updatedLine = nil + for i = 0, 6 do -- Find the menu line for this value + local line = MenuLines[i] + if line.Type ~= 0 then + if line.Type ~= LT_MENU and line.ValId == valId then -- identifier of ValueId stored in the line + line.Val = value + ctx_CurLine = i + --updatedLine = line + + updateValText(line) + + local debugTxt = line.Val + if isListLine(line) then + debugTxt = line.ValText .. " [" .. value .. "]" + end + + LOG_write("RX: Value Updated: #%d VId=0x%04X Value=%s\n", i, valId, debugTxt) + break + end + end + end + + --if (updatedLine == nil) then + -- LOG_write("Cannot Find Line for ValueId=%x\n", valId) + --end + Phase = PH_VALUES + + elseif cmd == 0x05 then -- Request TX info + ctx_CurLine = multiBuffer(12) + TX_Info_Type = multiBuffer(13) + TX_Info_Step = 0 + Phase = PH_TX_INFO + LOG_write("RX:TXInfoReq: Port=%d T=0x%02X\n", ctx_CurLine, TX_Info_Type) + + elseif cmd == 0xA7 then -- RX EXIT Request + if Phase == PH_EXIT_REQ then -- Response to our EXIT req + Phase = PH_EXIT_DONE + else -- Unexpected RX Exit + DSM_Release() + error("RX Connection Drop") + end + + elseif cmd == 0x00 then -- RX Heartbeat + LOG_write("RX:RxHb\n") + end + + return cmd +end + + +local function DSM_Send_Receive() + + -- Receive part: Process incoming messages if there is nothing to send + if SendDataToRX==0 and multiBuffer(10) == 0x09 then + local cmd = DSM_ProcessResponse() + -- Data processed + multiBuffer(10, 0x00) + RXInactivityTime = getTime() + 800 -- Reset Inactivity timeout (8s) + + if (cmd > 0x00) then -- RX-HeartBeat?? + -- Only change to SEND mode if we received a valid response (Ignore heartbeat) + SendDataToRX = 1 + end + else + -- Check if enouth time has passed from last Received activity + if (getTime() > RXInactivityTime and Phase~=PH_RX_VER and Phase~= PH_EXIT_DONE) then + if (isEditing()) then -- If Editing, extend time + RXInactivityTime = getTime() + 400 + else + DSM_Release() + error("RX Disconnected") + end + end + end + + -- Sending part -- + if SendDataToRX == 1 then + SendDataToRX = 0 + DSM_SendRequest() + TXInactivityTime = getTime() + 200 -- Reset Inactivity timeout (2s) + else + -- Check if enouth time has passed from last transmit activity + if getTime() > TXInactivityTime then + SendDataToRX = 1 -- Switch to Send mode to send heartbeat + + -- Change to Idle/HB mode if we are wating for RX version + if Phase ~= PH_RX_VER then + -- Phase = If IsEditing then PH_VAL_EDITING else PH_WAIT_CMD + Phase = (isEditing() and PH_VAL_EDITING) or PH_WAIT_CMD + end + end + end +end + +----- + +local function showBitmap(x, y, imgDesc) + local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|' + local imgName, imgMsg = f(), f() + + f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':' + local p1, p2 = f(), f() + + lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG + lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG +end + + +local function drawButton(x, y, text, active) + local attr = TEXT_ATTR + if (active) then attr = attr + INVERS end + lcd.drawText(x, y, text, attr) +end + +local ver_rx_count = 0 + +local function DSM_Display() + lcd.clear() + --Draw RX Menu + if Phase == PH_RX_VER then + lcd.drawText(1, 0, "DSM Frwd Prog "..VERSION, INVERS) + + local msgId = 0x300 -- Waiting for RX + if (ctx_isReset) then msgId=0x301 end -- Waiting for Reset + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, Get_Text(msgId), BLINK) + return + end + + -- display Program version or RX version + local msg = RX_Name .. " v" .. RX_Version + ver_rx_count = ver_rx_count + 1 + if (ver_rx_count > 50) then + msg = "FProg "..VERSION + if (ver_rx_count > 100) then ver_rx_count=0 end + end + lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) + + if Menu.MenuId == 0 then return end; -- No Title yet + + -- Got a Menu + lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS) + + if (Phase == PH_TX_INFO) then + lcd.drawText(1, 3 * LCD_Y_LINE_HEIGHT, "Sending CH"..(ctx_CurLine+1), TEXT_ATTR) + end + + local y = LCD_Y_LINE_HEIGHT + 2 + for i = 0, 6 do + local attrib = TEXT_ATTR + if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line + + local line = MenuLines[i] + + if line.Type ~= 0 then + local heading = line.Text + + if (line.TextId >= 0x8000) then -- Flight mode + heading = " " .. Flight_Mode .. " " + if (line.Val==nil) then heading = heading .. "--" else heading = heading .. ((line.Val or 0) + 1) end + else + local text = nil + if line.Type ~= LT_MENU then -- list/value + if line.Val ~= nil then -- Value to display?? + -- text = line.Val + text = line.ValText + + if isListLine(line) then + local textId = line.Val + line.TextStart + --text = Get_Text_Value(textId) + + -- image?? + local offset = 0 + if (line.Type==LT_LIST_ORI) then offset = offset + 0x100 end --FH6250 hack + local imgDesc = GetTextFromFile(List_Text_Img[textId+offset]) + + if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value + showBitmap(1, 20, imgDesc) + end + end + end -- Value + + if (ctx_EditLine == i) then -- Editing a Line + attrib = BLINK + INVERS + TEXT_ATTR + end + lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value + attrib = TEXT_ATTR + end -- Line with value/list + end -- not Flight mode + lcd.drawText(1, y, heading, attrib) -- display text + end + y = y + LCD_Y_LINE_HEIGHT + end -- for + + if Menu.BackId~=0 then + drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1) + end + + if Menu.NextId~=0 then + drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7) + end + + if Menu.PrevId~=0 then + drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8) + end +end + +----------------------------------------------------------------------------------------- + +local function load_msg_from_file(fileName, offset, FileState) + + if (FileState.state==nil) then -- Initial State + FileState.state=1 + FileState.lineNo=0 + FileState.filePos=0 + end + + if FileState.state==1 then + for l=1,10 do -- do 10 lines at a time + local type, sIndex, text + local lineStart = FileState.filePos + + type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos+offset) + + --print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos)) + + if (lineStart==FileState.filePos) then -- EOF + FileState.state=2 --EOF State + return 1 + end + FileState.lineNo = FileState.lineNo + 1 + + type = rtrim(type) + + if (string.len(type) > 0 and string.len(sIndex) > 0) then + local index = tonumber(sIndex) + local filePos = lineStart + offset + + if (index == nil) then + assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex)) + elseif (type == "T") then + Text[index] = filePos + elseif (type == "LT") then + List_Text[index] = filePos + elseif (type == "LI") then + List_Text_Img[index] = filePos + elseif (type == "FM") then + Flight_Mode = text + elseif (type == "RX") then + RxName[index] = text + else + assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type)) + end + end + gc() + end -- for + end -- if + + return 0 +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + --LOG_open() + --LOG_write("--- NEW SESSION\n") + + --DSM_Init_Model() + + --Set protocol to talk to + multiBuffer(0, string.byte('D')) + --test if value has been written + if multiBuffer(0) ~= string.byte('D') then + error("Not enough memory!") + return 2 + end + + if (LCD_W > 128) then + TEXT_ATTR = 0 + LCD_Y_LINE_HEIGHT = 25 + LCD_X_MAX = 300 + LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30 + + LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + end + + Phase = PH_INIT +end + + +----------------------------------------------------------------------------------------------------------- +local initStep=0 +local FileState = { lineNo=0 } + +local function Inc_Init() + lcd.clear() + + lcd.drawText(1, 0, "Loading Msg file: "..(FileState.lineNo or 0)) + if (initStep == 0) then + if (load_msg_from_file(MSG_FILE, 0, FileState)==1) then + initStep=1 + FileState = {} + end + else + Phase = PH_RX_VER -- Done Init + DSM_Connect() + end +end + +------------------------------------------------------------------------------------------------------------ +-- Main + +local function DSM_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + if (Phase == PH_INIT) then + Inc_Init() -- Incremental initialization + return 0 + end + + DSM_Display() + DSM_HandleEvent(event) + DSM_Send_Receive() + gc() + + if Phase == PH_EXIT_DONE then + DSM_Release() + LOG_close() + return 2 + else + return 0 + end +end + +--- + gc() + local M_DATA = {} + + -- Load Model Configuration + local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P1.lua"), "Mising: DsmMIN_P1.lua") + (MODEL, M_DATA, LOG_write) + gc() + if (r==1) then + -- Translate model Configuration to DSMDATA + local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P2.lua"), "Missing DsmMIN_P2.lua") + (MODEL, M_DATA, LOG_write) + + MODEL.PORT_TEXT = nil + --MODEL.TX_CH_TEXT = {} + gc() + else + error("Cannot load Model Config") + end + M_DATA = nil + gc() +--- + +return { init = DSM_Init, run = DSM_Run } diff --git a/SCRIPTS/TOOLS/DSM FwdPrg_56_STUP.lua b/SCRIPTS/TOOLS/DSM FwdPrg_56_STUP.lua new file mode 100644 index 0000000..efadc83 --- /dev/null +++ b/SCRIPTS/TOOLS/DSM FwdPrg_56_STUP.lua @@ -0,0 +1,951 @@ +local toolName = "TNS|DSM Frwd Prog v0.56a (MIN-SETUP)|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 VERSION = "v0.56" +local DSMLIB_PATH = "/SCRIPTS/TOOLS/DSMLIB/" +local DATA_PATH = "/MODELS/DSMDATA" + +local LOG_FILE = "/LOGS/dsm_min_log.txt" + +-- Phase +local PH_INIT = 0 +local PH_RX_VER, PH_TITLE = 1, 2 +local PH_VAL_CHANGING, PH_VAL_EDITING, PH_VAL_EDIT_END = 6, 7, 8 +local PH_WAIT_CMD, PH_EXIT_REQ, PH_EXIT_DONE = 9, 10, 11 + +-- Line Types +local LT_MENU, LT_LIST_NC = 0x1C, 0x6C + +local Phase = PH_INIT + +local Text = {} +local List_Text = {} +local List_Text_Img = {} + +local originalValue = 0 + +local ctx_SelLine = 0 -- Current Selected Line +local ctx_EditLine = nil -- Current Editing Line + +local Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 } +local MenuLines = {} + +local logFile = nil + +local LCD_W_BUTTONS = 19 +local LCD_H_BUTTONS = 10 + +local LCD_X_MAX = 128 +local LCD_X_RIGHT_BUTTONS = LCD_X_MAX - LCD_W_BUTTONS - 1 + +local LCD_Y_LINE_HEIGHT = 7 +local LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + +local TEXT_ATTR = SMLSIZE + +local TX_CHANNELS = 12 + +local AT_PLANE = 0 + +local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"} + +local WT_A1 = 0 +local WT_A2 = 1 +local WT_FLPR = 2 +local WT_A1_F1 = 3 +local WT_A2_F1 = 4 +local WT_A2_F2 = 5 +local WT_ELEVON_A = 6 +local WT_ELEVON_B = 7 + +local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"} + +local TT_R1 = 0 +local TT_R1_E1 = 1 +local TT_R1_E2 = 2 +local TT_R2_E1 = 3 +local TT_R2_E2 = 4 +local TT_VT_A = 5 +local TT_VT_B = 6 +local TT_TLRN_A = 7 +local TT_TLRN_B = 8 +local TT_TLRN_A_R2 = 9 +local TT_TLRN_B_R2 = 10 + +local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele", + "VTail A","VTail B","Taileron A","Taileron B", + "Taileron A + Dual Rud","Taileron B + Dual Rud" + } + +local MT_NORMAL = 0 +local MT_REVERSE = 1 + +local P1 = 0 +local P2 = 1 +local P3 = 2 +local P4 = 3 +local P5 = 4 +local P6 = 5 +local P7 = 6 +local P8 = 7 +--local P9 = 8 +--local P10 = 9 + +local MV_AIRCRAFT_TYPE = 1001 +local MV_WING_TYPE = 1002 +local MV_TAIL_TYPE = 1003 + +local MV_CH_BASE = 1010 +local MV_CH_THR = 1010 + +local MV_CH_L_AIL = 1011 +local MV_CH_R_AIL = 1012 +local MV_CH_L_FLP = 1013 +local MV_CH_R_FLP = 1014 + +local MV_CH_L_RUD = 1015 +local MV_CH_R_RUD = 1016 +local MV_CH_L_ELE = 1017 +local MV_CH_R_ELE = 1018 + +local MV_PORT_BASE = 1020 +local MV_P1_MODE = 1020 +--local MV_P2_MODE = 1021 +--local MV_P3_MODE = 1022 +--local MV_P4_MODE = 1023 +--local MV_P5_MODE = 1024 +local MV_P6_MODE = 1025 +--local MV_P7_MODE = 1026 +--local MV_P8_MODE = 1027 +--local MV_P9_MODE = 1028 +--local MV_P10_MODE = 1029 + +local MV_DATA_END = 1040 + +-- MENU DATA Management +local M_DB = {} -- Store the variables used in the Menus. + +local lastGoodMenu=0 + +local currATyp = -1 +local currTTyp = -1 +local currWTyp = -1 + +local menuDataChanged = false + +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + hashName = nil, + modelOutputChannel = {}, -- Output information from OTX/ETX + + TX_CH_TEXT= { }, + PORT_TEXT = { }, + + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script +} + +local function gc() + collectgarbage("collect") +end + +--[[ +local function gcTable(t) + if type(t)=="table" then + for i,v in pairs(t) do + if type(v) == "table" then + gcTable(v) + end + t[i] = nil + end + end + gc() + return t +end +--]] + +local function LOG_open() + logFile = io.open(LOG_FILE, "w") -- Truncate Log File +end + +local function LOG_write(...) + if (logFile == nil) then LOG_open() end + local str = string.format(...) + io.write(logFile, str) +end + +local function LOG_close() + if (logFile ~= nil) then io.close(logFile) end +end + +-- Saves MENU_DATA to a file +local function ST_SaveFileData() + local fname = MODEL.hashName + + print("Saving File:"..fname) + local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File + + -- Foreach MENU_DATA with a value write Var_Id:Value into file + for i = 0, MV_DATA_END do + if (M_DB[i]~=nil) then + io.write(dataFile,string.format("%s:%s\n",i,M_DB[i])) + end + end + io.close(dataFile) +end + +local function tailTypeCompatible(a,b) + + local function normalize(tt) + if (tt==TT_TLRN_A or tt==TT_TLRN_B) then + return TT_TLRN_A + elseif (tt==TT_TLRN_A_R2 or tt==TT_TLRN_B_R2) then + return TT_TLRN_A_R2 + elseif (tt==TT_VT_A or tt==TT_VT_B) then + return TT_VT_A + else + return tt + end + end + + return (normalize(a)==normalize(b)) +end + +local function ST_PlaneWingInit(wingType) + --print("Change Plane WingType:"..wing_type_text[wingType]) + + M_DB[MV_WING_TYPE] = wingType + + -- Clear all Wing Data + M_DB[MV_CH_L_AIL] = nil + M_DB[MV_CH_R_AIL] = nil + M_DB[MV_CH_L_FLP] = nil + M_DB[MV_CH_R_FLP] = nil + + M_DB[MV_CH_THR] = P1 + + -- Default Channel Assisgments for each Wing type + + if (wingType==WT_A1) then + M_DB[MV_CH_L_AIL] = P2 + elseif (wingType==WT_A2 or wingType==WT_FLPR) then + M_DB[MV_CH_L_AIL] = P6 + M_DB[MV_CH_R_AIL] = P2 + elseif (wingType==WT_A1_F1) then + M_DB[MV_CH_L_AIL] = P2 + M_DB[MV_CH_L_FLP] = P6 + elseif (wingType==WT_A2_F1) then + M_DB[MV_CH_L_AIL] = P6 + M_DB[MV_CH_R_AIL] = P2 + M_DB[MV_CH_L_FLP] = P5 + elseif (wingType==WT_A2_F2) then + M_DB[MV_CH_L_AIL] = P6 + M_DB[MV_CH_R_AIL] = P2 + M_DB[MV_CH_R_FLP] = P5 + M_DB[MV_CH_L_FLP] = P7 + elseif (wingType==WT_ELEVON_A) then + M_DB[MV_CH_L_AIL] = P2 + M_DB[MV_CH_R_AIL] = P3 + elseif (wingType==WT_ELEVON_B) then + M_DB[MV_CH_L_AIL] = P3 + M_DB[MV_CH_R_AIL] = P2 + else -- Assume normal + print("ERROR: Invalid Wing Type") + end +end + +local function ST_PlaneTailInit(tailType) + if (M_DB[MV_WING_TYPE]==WT_ELEVON_A or + M_DB[MV_WING_TYPE]==WT_ELEVON_B) then + tailType = TT_R1 -- Delta only have ruder + end + + --print("Change Plane Tail Type:"..tail_type_text[tailType]) + + -- Clear all data for Tail + M_DB[MV_TAIL_TYPE] = tailType + M_DB[MV_CH_L_ELE] = nil + M_DB[MV_CH_R_ELE] = nil + M_DB[MV_CH_L_RUD] = nil + M_DB[MV_CH_R_RUD] = nil + + -- Setup Channels for different Tail types + if (tailType == TT_R1) then + M_DB[MV_CH_L_RUD] = P4 + elseif (tailType == TT_R1_E1) then + M_DB[MV_CH_L_ELE] = P3 + M_DB[MV_CH_L_RUD] = P4 + elseif (tailType == TT_R1_E2) then + M_DB[MV_CH_L_ELE] = P5 + M_DB[MV_CH_R_ELE] = P3 + M_DB[MV_CH_L_RUD] = P4 + elseif (tailType == TT_R2_E1) then + M_DB[MV_CH_L_ELE] = P3 + M_DB[MV_CH_L_RUD] = P4 + M_DB[MV_CH_R_RUD] = P5 + elseif (tailType == TT_R2_E2) then + M_DB[MV_CH_L_ELE] = P5 + M_DB[MV_CH_R_ELE] = P3 + M_DB[MV_CH_L_RUD] = P4 + M_DB[MV_CH_R_RUD] = P6 + elseif (tailType == TT_VT_A or tailType == TT_VT_B) then + M_DB[MV_CH_L_ELE] = P3 + M_DB[MV_CH_R_ELE] = P4 + elseif (tailType == TT_TLRN_A or tailType == TT_TLRN_B or + tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then + M_DB[MV_CH_L_RUD] = P4 + M_DB[MV_CH_L_ELE] = P5 + M_DB[MV_CH_R_ELE] = P3 + else -- Assume Normal + print("ERROR:invalid Tail Type") + end + + if (tailType == TT_TLRN_A_R2 or tailType == TT_TLRN_B_R2) then + M_DB[MV_CH_R_RUD] = P8 + end +end + +local function ST_AircraftInit(aircraftType) + M_DB[MV_AIRCRAFT_TYPE] = aircraftType + ST_PlaneWingInit(WT_A1) + ST_PlaneTailInit(TT_R1_E1) +end + + +-- Setup Initial Default Data for the Menus +local function ST_Default_Data() + ST_AircraftInit(AT_PLANE) + + for i=0,9 do + M_DB[MV_P1_MODE+i] = MT_NORMAL + MODEL.modelOutputChannel[P1+i].revert + end +end + +local function MenuLinePostProcessing(line) + line.MenuId = Menu.MenuId + + if line.Type == LT_MENU then + -- nothing to do on menu entries + line.Val=nil + elseif line.Type == LT_LIST_NC then + -- Normalize Min/Max to be relative to Zero + line.TextStart = line.Min + line.Def = line.Def - line.Min -- normalize default value + line.Max = line.Max - line.Min -- normalize max index + line.Min = 0 -- min index + end +end + + +local function portUse(p) + local out = nil + if p==M_DB[MV_CH_THR] then out = "Thr" + elseif p == M_DB[MV_CH_L_AIL] then + out=(M_DB[MV_CH_R_AIL] and "Ail_L") or "Ail" + elseif p == M_DB[MV_CH_R_AIL] then out="Ail_R" + elseif p == M_DB[MV_CH_L_ELE] then + out=(M_DB[MV_CH_R_ELE] and "Ele_L") or "Ele" + elseif p == M_DB[MV_CH_R_ELE] then out="Ele_R" + elseif p == M_DB[MV_CH_L_RUD] then + out=(M_DB[MV_CH_R_RUD] and "Rud_L") or "Rud" + elseif p == M_DB[MV_CH_R_RUD] then out="Rud-R" + elseif p == M_DB[MV_CH_L_FLP] then + out=(M_DB[MV_CH_R_FLP] and "Flp_L") or "Flp" + elseif p == M_DB[MV_CH_R_FLP] then out="Flp_R" + else + out = "" + end + return out +end + +-- Creates the menus to Render with the GUI +local function ST_LoadMenu(menuId) + + local function Header(p) + return MODEL.PORT_TEXT[p].." "..portUse(p) + end + + local function generateGyroReverse(menuId, P_BASE, V_BASE) + for i=0,4 do + MenuLines[i] = { Type = LT_LIST_NC, Text=Header(P_BASE+i), TextId = 0, ValId = V_BASE+i, Min=45, Max=46, Def=45, Val=M_DB[V_BASE+i] } + end + + MenuLines[5] = { Type = LT_MENU, Text="Only TAER affects AS3X/SAFE react dir", TextId = 0, ValId = menuId } + MenuLines[6] = { Type = LT_MENU, Text="If changes, RX 'Relearn Servo'", TextId = 0, ValId = menuId } + + ctx_SelLine = 0 + end + + -- Begin + for i = 0, 6 do -- clear menu + MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0 } + end + + + if (menuId==0x1000) then -- MAIN MENU + Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + + if (true) then + MenuLines[4] = { Type = LT_MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 } + MenuLines[5] = { Type = LT_MENU, Text="Discard Changes", TextId = 0, ValId = 0xFFF9 } + ctx_SelLine = 4 + end + lastGoodMenu = menuId + elseif (menuId==0x1001) then -- MODEL SETUP + local backId = 0xFFF9 -- No changes, just exit + local title = "Setup ("..MODEL.modelName..")" + if (menuDataChanged) then + backId = 0x1000 -- Go to Save menu + title = title.." *" + end + Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 } + MenuLines[0] = { Type = LT_MENU, Text = "Aircraft Setup", ValId = 0x1010,TextId=0 } + MenuLines[1] = { Type = LT_MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 } + MenuLines[3] = { Type = LT_MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 } + MenuLines[5] = { Type = LT_MENU, Text = "WARNING: Changing of Aircraft", ValId = 0x1001, TextId=0 } + MenuLines[6] = { Type = LT_MENU, Text = "deletes prev Ch/Port assgmt.", ValId = 0x1001, TextId=0 } + + ctx_SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1005) then + ST_SaveFileData() + menuDataChanged = false + + local msg1 = "Data saved to: " + local msg2 = " ../DSMLIB/"..MODEL.hashName + + Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + MenuLines[2] = { Type = LT_MENU, Text=msg1, TextId = 0, ValId = 0x1005 } + MenuLines[3] = { Type = LT_MENU, Text=msg2, TextId = 0, ValId = 0x1005 } + MenuLines[6] = { Type = LT_MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 } + ctx_SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1010) then + Menu = { MenuId = 0x1010, Text = "Aircraft", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 } + MenuLines[5] = { Type = LT_LIST_NC, Text="Aircraft Type", TextId = 0, ValId = MV_AIRCRAFT_TYPE, Min=15, Max=15, Def=15, Val=M_DB[MV_AIRCRAFT_TYPE] } + ctx_SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1011) then + Menu = { MenuId = 0x1011, Text = "Model Type: "..aircraft_type_text[currATyp], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 } + MenuLines[5] = { Type = LT_LIST_NC, Text="Wing Type", TextId = 0, ValId = MV_WING_TYPE, Min=20, Max=27, Def=20, Val=M_DB[MV_WING_TYPE] } + MenuLines[6] = { Type = LT_LIST_NC, Text="Tail Type", TextId = 0, ValId = MV_TAIL_TYPE, Min=30, Max=40, Def=30, Val=M_DB[MV_TAIL_TYPE] } + ctx_SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1020) then + ------ WING SETUP ------- + local thr = M_DB[MV_CH_THR] + local leftAil = M_DB[MV_CH_L_AIL] + local rightAil = M_DB[MV_CH_R_AIL] + local leftFlap = M_DB[MV_CH_L_FLP] + local rightFlap = M_DB[MV_CH_R_FLP] + + local thrText = "Thr" + local leftAilText = "Left Ail" + local rightAilText = "Right Ail" + local leftFlapText = "Left Flap" + local rightFlapText = "Right Flap" + + if (rightAil==nil) then leftAilText = "Aileron" end + if (rightFlap==nil) then leftFlapText = "Flap" end + + local title = aircraft_type_text[currATyp].." Wing:"..wing_type_text[currWTyp] + + Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 } + + MenuLines[0] = { Type = LT_LIST_NC, Text=thrText, TextId = 0, ValId = MV_CH_THR, Min=0, Max=10, Def=0, Val= thr } + + MenuLines[2] = { Type = LT_LIST_NC, Text=leftAilText, TextId = 0, ValId = MV_CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil } + + if (rightAil) then + MenuLines[3] = { Type = LT_LIST_NC, Text=rightAilText, TextId = 0, ValId = MV_CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil } + end + + if (leftFlap) then + MenuLines[4] = { Type = LT_LIST_NC, Text=leftFlapText, TextId = 0, ValId = MV_CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap } + end + if (rightFlap) then + MenuLines[5] = { Type = LT_LIST_NC, Text=rightFlapText, TextId = 0, ValId = MV_CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap } + end + + ctx_SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x1021) then + ------ TAIL SETUP ------- + local leftRud = M_DB[MV_CH_L_RUD] + local rightRud = M_DB[MV_CH_R_RUD] + local leftEle = M_DB[MV_CH_L_ELE] + local rightEle = M_DB[MV_CH_R_ELE] + + local leftRudText = "Left Rud" + local rightRudText = "Right Rud" + + local leftElvText = "Left Ele" + local rightElvText = "Right Ele" + + if (rightRud==nil) then leftRudText = "Rud" end + if (rightEle==nil) then leftElvText = "Ele" end + + local title = aircraft_type_text[currATyp].." Tail:"..tail_type_text[currTTyp] + + Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 } + if (leftRud) then + MenuLines[1] = { Type = LT_LIST_NC, Text=leftRudText, TextId = 0, ValId = MV_CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud} + end + + if (rightRud) then + MenuLines[2] = { Type = LT_LIST_NC, Text=rightRudText, TextId = 0, ValId = MV_CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud } + end + + if (leftEle) then + MenuLines[4] = { Type = LT_LIST_NC, Text=leftElvText, TextId = 0, ValId = MV_CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle } + end + + if (rightEle) then + MenuLines[5] = { Type = LT_LIST_NC, Text=rightElvText, TextId = 0, ValId = MV_CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle } + end + + ctx_SelLine = 1 + lastGoodMenu = menuId + + elseif (menuId==0x1030) then + Menu = { MenuId = 0x1030, Text = "Gyro Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 } + generateGyroReverse(menuId,P1,MV_P1_MODE) + lastGoodMenu = menuId + elseif (menuId==0x1031) then + Menu = { MenuId = 0x1031, Text = "Gyro Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 } + generateGyroReverse(menuId,P6,MV_P6_MODE) + lastGoodMenu = menuId + elseif (menuId==0xFFF9) then + ChangePhase(PH_EXIT_DONE) + return + else + Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx_SelLine = -1 -- BACK BUTTON + end + + for i = 0, 6 do + if (MenuLines[i].Type > 0) then + MenuLinePostProcessing(MenuLines[i]) + end + end + gc() +end + +-- Inital List and Image Text for this menus +local function ST_Init_Text(rxId) + -- Channel Names use the Port Text Retrived from OTX/ETX + local p = 0 + + for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end + List_Text[10] = "--" + + -- Aircraft Type + List_Text[15+AT_PLANE] = "Airplane"; + + -- Wing Types + p = 20+WT_A1; List_Text[p] = "Single Ail"; --List_Text_Img[p] = "x.png|Single Aileron" + p = 20+WT_A2; List_Text[p] = "Dual Ail"; --List_Text_Img[p] = "x.png|Dual Aileron" + p = 20+WT_FLPR; List_Text[p] = "Flaperon"; --List_Text_Img[p] = "x.png|Flaperon" + p = 20+WT_A1_F1; List_Text[p] = "Ail + Flap"; --List_Text_Img[p] = "x.png|Aileron + Flap" + p = 20+WT_A2_F1; List_Text[p] = "Dual Ail + Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Flap" + p = 20+WT_A2_F2; List_Text[p] = "Dual Ail + Dual Flap"; --List_Text_Img[p] = "x.png|Dual Aileron + Dual Flap" + p = 20+WT_ELEVON_A; List_Text[p] = "Delta A"; --List_Text_Img[p] = "x.png|Delta/Elevon A" + p = 20+WT_ELEVON_B; List_Text[p] = "Delta B"; --List_Text_Img[p] = "x.png|Delta/Elevon B" + + -- Tail Types + p = 30+TT_R1; List_Text[p] = "Rudder Only"; --List_Text_Img[p] = "x.png|Rudder Only" + p = 30+TT_R1_E1; List_Text[p] = "Rud + Ele"; --List_Text_Img[p] = "x.png|Tail Normal" + p = 30+TT_R1_E2; List_Text[p] = "Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Rud + Dual Ele" + p = 30+TT_R2_E1; List_Text[p] = "Dual Rud + Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Ele" + p = 30+TT_R2_E2; List_Text[p] = "Dual Rud + Dual Ele"; --List_Text_Img[p] = "x.png|Dual Rud + Dual Elev" + p = 30+TT_VT_A; List_Text[p] = "V-Tail A"; --List_Text_Img[p] = "x.png|V-Tail A" + p = 30+TT_VT_B; List_Text[p] = "V-Tail B"; --List_Text_Img[p] = "x.png|V-Tail B" + p = 30+TT_TLRN_A; List_Text[p] = "Taileron A"; --List_Text_Img[p] = "x.png|Taileron A" + p = 30+TT_TLRN_B; List_Text[p] = "Taileron B"; --List_Text_Img[p] = "x.png|Taileron B" + p = 30+TT_TLRN_A_R2; List_Text[p] = "Taileron A + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron A + Dual Rud" + p = 30+TT_TLRN_B_R2; List_Text[p] = "Taileron B + 2x Rud"; --List_Text_Img[p] = "x.png|Taileron B + Dual Rud" + + -- Servo Reverse + List_Text[45+MT_NORMAL] = "Normal" + List_Text[45+MT_REVERSE] = "Reverse" +end + +-- Initial Setup +local function ST_Init() + ST_Init_Text(0) + gc() + + -- Setup default Data if no data loaded + menuDataChanged = false + if (M_DB[MV_AIRCRAFT_TYPE]==nil) then + ST_Default_Data() + menuDataChanged = true + end + + currATyp = M_DB[MV_AIRCRAFT_TYPE] + currWTyp = M_DB[MV_WING_TYPE] + currTTyp = M_DB[MV_TAIL_TYPE] + + Phase = PH_RX_VER +end + +----- Line Type + +local function isSelectable(line) + if (line.Type == LT_MENU and line.ValId == line.MenuId) then return false end -- Menu to same page + if (line.Type ~= LT_MENU and line.Max == 0) then return false end -- Read only data line + if (line.Type ~= 0 and line.TextId < 0x8000) then return true end -- Not Flight Mode + return false; +end + +local function isListLine(line) + return line.Type==LT_LIST_NC +end + +local function isEditing() + return ctx_EditLine ~= nil +end + +----------------------- +local function Get_Text(index) + local out = Text[index] or string.format("Unknown_%X", index) + return out +end + +local function Get_Text_Value(index) + local out = List_Text[index] or Get_Text(index) + return out +end + +function ChangePhase(newPhase) + Phase = newPhase +end + +local function Value_Add(dir) + local line = MenuLines[ctx_SelLine] + local inc = dir + + line.Val = line.Val + inc + + if line.Val > line.Max then + line.Val = line.Max + elseif line.Val < line.Min then + line.Val = line.Min + end +end +-------------- + +local function GotoMenu(menuId, lastSelectedLine) + Menu.MenuId = menuId + ctx_SelLine = lastSelectedLine + ChangePhase(PH_TITLE) +end + +local function DSM_HandleEvent(event) + if event == EVT_VIRTUAL_EXIT then + if Phase == PH_RX_VER then + Phase = PH_EXIT_DONE -- Exit program + else + if isEditing() then -- Editing a Line, need to restore original value + MenuLines[ctx_EditLine].Val = originalValue + event = EVT_VIRTUAL_ENTER + else + if (Menu.BackId > 0 ) then -- Back?? + ctx_SelLine = -1 --Back Button + event = EVT_VIRTUAL_ENTER + else + ChangePhase(PH_EXIT_REQ) + end + end + end + end -- Exit + + if Phase == PH_RX_VER then return end -- nothing else to do + + if event == EVT_VIRTUAL_NEXT then + if isEditing() then -- Editting? + Value_Add(1) + else + if ctx_SelLine < 7 then -- On a regular line + local num = ctx_SelLine -- Find the prev selectable + for i = ctx_SelLine + 1, 6, 1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + elseif Menu.PrevId ~= 0 then + ctx_SelLine = 8 -- Prev + end + end + return + end + + if event == EVT_VIRTUAL_PREV then + if isEditing() then -- In Edit Mode + Value_Add(-1) + else + if ctx_SelLine == 8 and Menu.NextId ~= 0 then + ctx_SelLine = 7 -- Next + elseif ctx_SelLine > 0 then + if ctx_SelLine > 6 then + ctx_SelLine = 7 --NEXT + end + local num = ctx_SelLine -- Find Prev Selectable line + for i = ctx_SelLine - 1, 0, -1 do + local line = MenuLines[i] + if isSelectable(line) then + ctx_SelLine = i + break + end + end + if num == ctx_SelLine then -- No Selectable Line + if (Menu.BackId > 0) then + ctx_SelLine = -1 -- Back + end + end + else + ctx_SelLine = -1 -- Back + end + end + return + end + + + if event == EVT_VIRTUAL_ENTER then + if ctx_SelLine == -1 then -- Back + GotoMenu(Menu.BackId, 0x80) + elseif ctx_SelLine == 7 then -- Next + GotoMenu(Menu.NextId, 0x82) + elseif ctx_SelLine == 8 then -- Prev + GotoMenu(Menu.PrevId, 0x81) + elseif ctx_SelLine >= 0 and MenuLines[ctx_SelLine].Type == LT_MENU then + GotoMenu(MenuLines[ctx_SelLine].ValId, ctx_SelLine) -- ValId is the next menu + else + -- value entry + if isEditing() then + ctx_EditLine = nil -- Done Editting + ChangePhase(PH_VAL_EDIT_END) + else -- Start Editing + ctx_EditLine = ctx_SelLine + originalValue = MenuLines[ctx_SelLine].Val + ChangePhase(PH_VAL_EDITING) + end + end + end +end + +local function DSM_Send_Receive() + + if Phase == PH_RX_VER then -- request RX version + Phase = PH_TITLE + Menu.MenuId = 0x01001 + Refresh_Display = true + elseif Phase == PH_WAIT_CMD then + + elseif Phase == PH_TITLE then -- request menu title + ST_LoadMenu(Menu.MenuId) + if (Phase~=PH_EXIT_DONE) then + Phase = PH_WAIT_CMD + end + Refresh_Display = true + elseif Phase == PH_VAL_EDIT_END then -- send value + local line = MenuLines[ctx_SelLine] -- Updated Value of SELECTED line + + -- Update the menu data from the line + if (M_DB[line.ValId] ~= line.Val ) then + M_DB[line.ValId] = line.Val + print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val)) + menuDataChanged=true + end + + -- Did the Wing type change? + local wt = M_DB[MV_WING_TYPE] + if (currWTyp ~= wt) then + currWTyp = wt + ST_PlaneWingInit(currWTyp) + + -- DELTA has only RUDER + if (currWTyp==WT_ELEVON_A or currWTyp==WT_ELEVON_B) then + M_DB[MV_TAIL_TYPE] = TT_R1 + end + end + + --- Did the tail changed? + local tt = M_DB[MV_TAIL_TYPE] + if (currTTyp ~= tt) then + if (not tailTypeCompatible(currTTyp,tt)) then + ST_PlaneTailInit(tt) + end + currTTyp = tt + end + + Phase = PH_WAIT_CMD + elseif Phase == PH_EXIT_REQ then + Phase=PH_EXIT_DONE + end +end + +----- + +local function showBitmap(x, y, imgDesc) + local f = string.gmatch(imgDesc, '([^%|]+)') -- Iterator over values split by '|' + local imgName, imgMsg = f(), f() + + f = string.gmatch(imgMsg or "", '([^%:]+)') -- Iterator over values split by ':' + local p1, p2 = f(), f() + + lcd.drawText(x, y, p1 or "", TEXT_ATTR) -- Alternate Image MSG + lcd.drawText(x, y + LCD_Y_LINE_HEIGHT, p2 or "", TEXT_ATTR) -- Alternate Image MSG + gc() +end + + +local function drawButton(x, y, text, active) + local attr = TEXT_ATTR + if (active) then attr = attr + INVERS end + lcd.drawText(x, y, text, attr) +end + +local function DSM_Display() + lcd.clear() + --Draw RX Menu + if Phase == PH_RX_VER then + return + end + + -- display Program version or RX version + local msg = "FProg "..VERSION + lcd.drawText(40, LCD_Y_LOWER_BUTTONS, msg, TEXT_ATTR) + + if Menu.MenuId == 0 then return end; -- No Title yet + + -- Got a Menu + lcd.drawText(1, 0, Menu.Text, TEXT_ATTR + INVERS) + + local y = LCD_Y_LINE_HEIGHT + 2 + for i = 0, 6 do + local attrib = TEXT_ATTR + if (i == ctx_SelLine) then attrib = attrib + INVERS end -- Selected Line + + local line = MenuLines[i] + + if line ~= nil and line.Type ~= 0 then + local heading = line.Text + + local text = nil + if line.Type ~= LT_MENU then -- list/value + if line.Val ~= nil then + if isListLine(line) then + local textId = line.Val + line.TextStart + text = Get_Text_Value(textId) + + --local imgDesc = List_Text_Img[textId] + + --if (imgDesc and i == ctx_SelLine) then -- Optional Image and Msg for selected value + -- showBitmap(1, 20, imgDesc) + --end + else + text = line.Val + end + end -- if is Value + + if (ctx_EditLine == i) then -- Editing a Line + attrib = BLINK + INVERS + TEXT_ATTR + end + lcd.drawText(LCD_X_MAX, y, text or "--", attrib + RIGHT) -- display value + --lcd.drawText(LCD_X_MAX, y, line.Format or "", TEXT_ATTR + RIGHT) -- display Format + attrib = TEXT_ATTR + end + + lcd.drawText(1, y, heading, attrib) -- display text + end + y = y + LCD_Y_LINE_HEIGHT + end -- for + + if Menu.BackId~=0 then + drawButton(LCD_X_RIGHT_BUTTONS, 0, "Back", ctx_SelLine == -1) + end + + if Menu.NextId~=0 then + drawButton(LCD_X_RIGHT_BUTTONS, LCD_Y_LOWER_BUTTONS, "Next", ctx_SelLine == 7) + end + + if Menu.PrevId~=0 then + drawButton(1, LCD_Y_LOWER_BUTTONS, "Prev", ctx_SelLine == 8) + end +end + +------------------------------------------------------------------------------------------------------------ +-- Init +local function DSM_Init() + --LOG_open() + ST_Init() + gc() + + if (LCD_W > 128) then + TEXT_ATTR = 0 + LCD_Y_LINE_HEIGHT = 25 + LCD_X_MAX = 300 + LCD_X_RIGHT_BUTTONS = LCD_X_MAX - 30 + + LCD_Y_LOWER_BUTTONS = (8 * LCD_Y_LINE_HEIGHT) + 2 + end + + Phase = PH_RX_VER +end + +-- Main + +local function DSM_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + DSM_Display() + DSM_HandleEvent(event) + DSM_Send_Receive() + gc() + + if Phase == PH_EXIT_DONE then + LOG_close() + return 2 + else + return 0 + end +end + +--- +-- Load Model Config +gc() +local r = assert(loadScript(DSMLIB_PATH.."DsmMIN_P1.lua"), "Not-Found: DSMLIB/DsmMIN_P1.lua") + (MODEL,M_DB, LOG_write) +gc() +---- +return { init = DSM_Init, run = DSM_Run } diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua new file mode 100644 index 0000000..e81759f --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmFwPrgLib.lua @@ -0,0 +1,813 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX/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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- This script library is a rewrite of the original DSM forward programming Lua +-- Script. The goal is to make it easier to understand, mantain, and to +-- separate the GUI from the DSM Forward programming engine/logic +-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc. + +-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module) +-- Rewrite/Enhancements By: Francisco Arzu +-- +------------------------------------------------------------------------------ + --############################################################################### + -- Multi buffer for DSM description + -- Multi_Buffer[0..2]=="DSM" -> Lua script is running + -- Multi_Buffer[3]==0x70+len -> TX to RX data ready to be sent + -- Multi_Buffer[4..9]=6 bytes of TX to RX data + -- Multi_Buffer[10..25]=16 bytes of RX to TX data + -- + -- To start operation: + -- Write 0x00 at address 3 + -- Write 0x00 at address 10 + -- Write "DSM" at address 0..2 + --############################################################################### + + +local Log, menuLib, modelLib, DEBUG_ON = ... -- Get Debug_ON from parameters. -- 0=NO DEBUG, 1=HIGH LEVEL 2=MORE DETAILS +local LIB_VERSION = "0.55" +local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt" + +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE + +local CH_TYPE = modelLib.CH_TYPE +local CH_MIX_TYPE = modelLib.CH_MIX_TYPE + +local DISP_ATTR = menuLib.DISP_ATTR +local DSM_Context = menuLib.DSM_Context +local MODEL = modelLib.MODEL + +local MAX_MENU_LINES = menuLib.MAX_MENU_LINES +local BACK_BUTTON = menuLib.BACK_BUTTON +local NEXT_BUTTON = menuLib.NEXT_BUTTON +local PREV_BUTTON = menuLib.PREV_BUTTON + + +local SEND_TIMEOUT = 2000 / 10 -- Home many 10ms intervals to wait on sending data to tx to keep connection open (2s) +local TXInactivityTime = 0 -- Next time to do heartbeat after inactivity +local RXInactivityTime = 0 -- To check RX disconnection + + +local TxInfo_Type = 0 +local TxInfo_Step = 0 +local Change_Step = 0 + +local IS_EDGETX = false + +------------------------------------------------------------------------------------------------------------ + +local function multiBuffer2String() -- used for debug + local i + local rxAnswer = "RX:" + for i = 10, 25 do + rxAnswer = rxAnswer .. string.format(" %02X", multiBuffer(i)) + end + return rxAnswer +end + +---------------- DSM Values <-> Int16 Manipulation -------------------------------------------------------- + +local function int16_LSB(number) -- Less Significat byte + local r,x = bit32.band(number, 0xFF) + return r +end + +local function int16_MSB(number) -- Most signifcant byte + return bit32.rshift(number, 8) +end + +local function Dsm_to_Int16(lsb, msb) -- Componse an Int16 value + return bit32.lshift(msb, 8) + lsb +end + +local function Dsm_to_SInt16(lsb,msb) -- Componse a SIGNED Int16 value + local value = bit32.lshift(msb, 8) + lsb + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function sInt16ToDsm(value) -- Convent to SIGNED DSM Value + if value < 0 then + value = 0x10000 + value + end + return value +end + +------------------------------------------------------------------------------------------------------------ +local function DSM_send(...) + local arg = { ... } + + for i = 1, #arg do + multiBuffer(3 + i, arg[i]) + end + multiBuffer(3, 0x70 + #arg) + + + if (DEBUG_ON > 1) then + local str = "" + for i = 1, #arg do + str = str .. string.format("%02X ", arg[i]) + end + LOG_write("DSM_SEND: [%s]\n", str) + end +end + + + +------------------------------------------------------------------------------------------------- +local function DSM_StartConnection() + if (DEBUG_ON) then Log.LOG_write("DSM_StartConnection()\n") end + + --Set protocol to talk to + multiBuffer( 0, string.byte('D') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('D') then + if (DEBUG_ON) then Log.LOG_write("Not Enouth memory\n") end + error("Not enough memory!") + return 2 + end + --Init TX buffer + multiBuffer( 3, 0x00 ) + --Init RX buffer + multiBuffer( 10, 0x00 ) + --Init telemetry + multiBuffer( 0, string.byte('D') ) + multiBuffer( 1, string.byte('S') ) + multiBuffer( 2, string.byte('M') ) + + return 0 +end + +local function DSM_ReleaseConnection() + if (DEBUG_ON) then Log.LOG_write("DSM_ReleaseConnection()\n") end + multiBuffer(0, 0) +end + +-------------------------------------------------------------------------------------------------------- +-- REEQUEST Messages to RX + +local function DSM_sendHeartbeat() + -- keep connection open + if (DEBUG_ON) then Log.LOG_write("SEND DSM_sendHeartbeat()\n") end + DSM_send(0x00, 0x04, 0x00, 0x00) +end + +local function DSM_getRxVerson() + local TX_CAP=0x14 -- Capabilities?? + local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc) + + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getRxVersion(Ch:0x%X,Cap:0x%X)\n",TX_MAX_CH,TX_CAP) end + DSM_send(0x11, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) +end + +local function DSM_getMainMenu() + local TX_CAP=0x14 -- Capabilities?? + local TX_MAX_CH = modelLib.TX_CHANNELS - 6 --number of channels after 6 (6Ch=0, 10ch=4, etc) + + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMainMenu(Ch:0x%X,Cap:0x%X) -- TX_Channels=%d\n",TX_MAX_CH,TX_CAP,TX_MAX_CH+6) end + DSM_send(0x12, 0x06, TX_MAX_CH, TX_CAP, 0x00, 0x00) -- first menu only +end + +local function DSM_getMenu(menuId, latSelLine) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getMenu(MenuId=0x%X LastSelectedLine=%s)\n", menuId, latSelLine) end + DSM_send(0x16, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, latSelLine) +end + +local function DSM_getFirstMenuLine(menuId) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getFirstMenuLine(MenuId=0x%X)\n", menuId) end + DSM_send(0x13, 0x04, int16_MSB(menuId), int16_LSB(menuId)) -- line 0 +end + +local function DSM_getNextMenuLine(menuId, curLine) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextLine(MenuId=0x%X,LastLine=%s)\n", menuId, curLine) end + DSM_send(0x14, 0x06, int16_MSB(menuId), int16_LSB(menuId), 0x00, curLine) -- line X +end + +local function DSM_getNextMenuValue(menuId, valId, text) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_getNextMenuValue(MenuId=0x%X, LastValueId=0x%X) Extra: Text=\"%s\"\n", menuId, valId, + text) + end + DSM_send(0x15, 0x06, int16_MSB(menuId), int16_LSB(menuId), int16_MSB(valId), int16_LSB(valId)) -- line X +end + +local function DSM_updateMenuValue(valId, val, text, line) + local value = sInt16ToDsm(val) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_updateValue(ValueId=0x%X,val=%d) Extra: Text=\"%s\" Value=%s\n", valId, val, text, menuLib.lineValue2String(line)) end + DSM_send(0x18, 0x06, int16_MSB(valId), int16_LSB(valId), int16_MSB(value), int16_LSB(value)) -- send current value +end + +local function DSM_validateMenuValue(valId, text, line) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_validateValue(ValueId=0x%X) Extra: Text=\"%s\" Value=%s\n", valId, text, menuLib.lineValue2String(line)) end + DSM_send(0x19, 0x04, int16_MSB(valId), int16_LSB(valId)) +end + +local function DSM_editingValue(lineNum, text, line) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValue(lineNo=0x%X) Extra: Text=\"%s\" Val=%s\n", lineNum, text, menuLib.lineValue2String(line)) end + DSM_send(0x1A, 0x04, int16_MSB(lineNum), int16_LSB(lineNum)) +end + +local function DSM_editingValueEnd(lineNum, text, line) + if (DEBUG_ON) then Log.LOG_write("SEND DSM_editingValueEnd(lineNo=0x%X) Extra: Text=\"%s\" Value=%s\n", lineNum, text, menuLib.lineValue2String(line)) end + DSM_send(0x1B, 0x04, int16_MSB(lineNum), int16_LSB(lineNum)) +end + +-- Send the functionality of the RX channel Port (channel) +local function DSM_sendTxChInfo_20(portNo) + local b1,b2 = MODEL.DSM_ChannelInfo[portNo][0] or 0, MODEL.DSM_ChannelInfo[portNo][1] or 0 + + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxChInfo(#%d DATA= %02X %02X %02X %02X) %s\n", portNo, + portNo, portNo, b1, b2, modelLib.channelType2String(b1,b2)) -- DATA part + end + DSM_send(0x20, 0x06, portNo, portNo, b1, b2) +end + +local function DSM_sendTxSubtrim_21(portNo) + local usage = MODEL.DSM_ChannelInfo[portNo][1] or 0 + local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10)) + local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10)) + local subTrim = math.floor(MODEL.modelOutputChannel[portNo].offset/10) + + -- Center at 100%: 142-1906 (0 8E 07 72) + local left = 142 + local right = 1906 + + if (bit32.band(usage,CH_TYPE.THR)>0) then + left = 0 + right = 2047 + end + + left = math.floor (left - (leftTravel -100) *8.8 + subTrim*2) + right = math.floor (right + (rightTravel -100) *8.8 + subTrim*2) + + if (left<0) then left=0 end + if (right>2027) then right=2047 end + + local b1,b2,b3,b4 = int16_MSB(left), int16_LSB(left), int16_MSB(right), int16_LSB(right) + + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxSubtrim(#%d DATA=%02X %02X %02X %02X) Range(%d - %d) ER L/R:(%d - %d)x8 ST:(%d)x2\n", portNo, + b1,b2,b3,b4, left, right, leftTravel-100, rightTravel-100, subTrim) -- DATA part + end + DSM_send(0x21, 0x06, b1,b2,b3,b4) -- Port is not send anywhere, since the previous 0x20 type message have it. +end + +local function DSM_sendTxServoTravel_23(portNo) + local leftTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].min/10)) + local rightTravel = math.abs(math.floor(MODEL.modelOutputChannel[portNo].max/10)) + local debugInfo = string.format("Travel L/R (%d - %d)",leftTravel,rightTravel) + + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxServoTravel(#%d DATA= %02X %02X %02X %02X) %s\n", portNo, + 0x00, leftTravel, 0x00, rightTravel, debugInfo) -- DATA part + end + DSM_send(0x23, 0x06, 0x00, leftTravel, 0x00, rightTravel) +end + +local function DSM_sentTxInfo(menuId,portNo) + -- TxInfo_Type=0 : AR636B Main Menu (Send port/Channel info + SubTrim + Travel) + -- TxInfo_Type=1 : AR630-637 Famly Main Menu (Only Send Port/Channel usage Msg 0x20) + -- TxInfo_Type=1F : AR630-637 Initial Setup/Relearn Servo Settings (Send port/Channel info + SubTrim + Travel +0x24/Unknown) + + if (TxInfo_Step == 0) then + -- AR630 family: Both TxInfo_Type (ManinMenu=0x1, Other First Time Configuration = 0x1F) + DSM_sendTxChInfo_20(portNo) + + if (TxInfo_Type == 0x1F) then + TxInfo_Step = 1 + end + if (TxInfo_Type == 0x00) then + TxInfo_Step = 2 + end + elseif (TxInfo_Step == 1) then + DSM_sendTxServoTravel_23(portNo) + TxInfo_Step = 2 + elseif (TxInfo_Step == 2) then + DSM_sendTxSubtrim_21(portNo) + + if (TxInfo_Type == 0x00) then + TxInfo_Step = 5 -- End Step + else + TxInfo_Step = 3 + end + elseif (TxInfo_Step == 3) then + -- 24,6: 0 83 5A B5 + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, + 0x00, 0x83, 0x5A, 0xB5) -- DATA part + end + DSM_send(0x24, 0x06, 0x00, 0x83, 0x5A, 0xB5) -- Still Uknown + TxInfo_Step = 4 + + elseif (TxInfo_Step == 4) then + -- 24,6: 6 80 25 4B + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo24(#%d DATA=0x24 0x06 %02X %02X %02X %02X)\n", portNo, + 0x06, 0x80, 0x25, 0x4B) -- DATA part + end + DSM_send(0x24, 0x06, 0x06, 0x80, 0x25, 0x4B) -- Still Uknown + TxInfo_Step = 5 + elseif (TxInfo_Step == 5) then + -- 22,4: 0 0 + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TxInfo_End(#%d)\n", portNo) + end + DSM_send(0x22, 0x04, 0x00, 0x00) + TxInfo_Step = 0 + end + + if (TxInfo_Step > 0) then + DSM_Context.SendDataToRX = 1 -- keep Transmitig + end +end + +----------------------------------------------------------------------------------------------------------- + +local function DSM_sendRequest() + -- Send the proper Request message depending on the Phase + + local ctx = DSM_Context + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + + if ctx.Phase == PHASE.RX_VERSION then -- request RX version + DSM_getRxVerson() + + elseif ctx.Phase == PHASE.WAIT_CMD then -- keep connection open + DSM_sendHeartbeat() + + elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title + if ctx.Menu.MenuId == 0 then -- First time loading a menu ? + DSM_getMainMenu() + else + DSM_getMenu(ctx.Menu.MenuId, ctx.SelLine) + + if (ctx.Menu.MenuId == 0x0001) then -- Executed the Reset Menu?? + if (DEBUG_ON) then Log.LOG_write("RX Reset!!!\n") end + -- Start again retriving RX info + ctx.Menu.MenuId = 0 + ctx.isReset = true + ctx.Phase = PHASE.RX_VERSION + end + end + + elseif ctx.Phase == PHASE.MENU_REQ_TX_INFO then + DSM_sentTxInfo(ctx.Menu.MenuId, ctx.CurLine) + + elseif ctx.Phase == PHASE.MENU_LINES then -- request next menu lines + if ctx.CurLine == -1 then -- No previous menu line loaded ? + DSM_getFirstMenuLine(ctx.Menu.MenuId) + else + DSM_getNextMenuLine(ctx.Menu.MenuId, ctx.CurLine) + end + + elseif ctx.Phase == PHASE.MENU_VALUES then -- request menu values + local line = ctx.MenuLines[ctx.CurLine] + DSM_getNextMenuValue(ctx.Menu.MenuId, line.ValId, line.Text) + + elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + + if (Change_Step==0) then + DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) + + if line.Type == menuLib.LINE_TYPE.LIST_MENU then -- Validation on every Step?? + Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after + else + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + end + else + DSM_validateMenuValue(line.ValId, line.Text, line) + Change_Step=0 + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + end + + elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then + local line = ctx.MenuLines[ctx.SelLine] + DSM_editingValue(line.lineNum, line.Text, line) + elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Update Value of SELECTED line + + if (Change_Step==0) then + DSM_updateMenuValue(line.ValId, line.Val, line.Text, line) + Change_Step=1; ctx.SendDataToRX=1 -- Send inmediatly after + elseif (Change_Step==1) then + DSM_validateMenuValue(line.ValId, line.Text, line) + Change_Step=2; ctx.SendDataToRX=1 -- Send inmediatly after + else + DSM_editingValueEnd(line.lineNum, line.Text, line) + Change_Step=0 + ctx.Phase = PHASE.WAIT_CMD + end + elseif ctx.Phase == PHASE.EXIT then + if (DEBUG_ON) then Log.LOG_write("CALL DSM_TX_Exit()\n") end + DSM_send(0x1F, 0x02, 0xFF, 0xFF) -- 0xAA + end +end + +----------------------------------------------------------------------------------------------------------- +-- Parsing Responses + +local function DSM_parseRxVersion() + --ex: 0x09 0x01 0x00 0x15 0x02 0x22 0x01 0x00 0x14 v2.22.1 00 14?? 8ch SAFE + -- 0x09 0x01 0x00 0x18 0x05 0x06 0x34 0x00 0x12 v5.6.52 00 12??? 6ch FC6250 + local rxId = multiBuffer(13) + DSM_Context.RX.Id = rxId + DSM_Context.RX.Name = menuLib.Get_RxName(rxId) + DSM_Context.RX.Version = multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) + if (DEBUG_ON) then Log.LOG_write("RESPONSE Receiver=%s Version %s Cap:0x%02X\n", + DSM_Context.RX.Name, DSM_Context.RX.Version, multiBuffer(18)) end +end + +local function DSM_parseMenu() + --ex: 0x09 0x02 0x4F 0x10 0xA5 0x00 0x00 0x00 0x50 0x10 0x10 0x10 0x00 0x00 0x00 0x00 + -- MenuID TextID PrevID NextID BackID + local ctx = DSM_Context + local menu = ctx.Menu + menu.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + menu.TextId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + menu.Text = menuLib.Get_Text(menu.TextId) + menu.PrevId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + menu.NextId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + menu.BackId = Dsm_to_Int16(multiBuffer(20), multiBuffer(21)) + for i = 0, MAX_MENU_LINES do -- clear menu + ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, Val=nil } + end + ctx.CurLine = -1 + + menuLib.MenuPostProcessing(menu) + + if (DEBUG_ON) then Log.LOG_write("RESPONSE Menu: %s\n", menuLib.menu2String(menu)) end + return menu +end + + +local function DSM_parseMenuLine() + --ex: 0x09 0x03 0x00 0x10 0x00 0x1C 0xF9 0x00 0x10 0x10 0x00 0x00 0x00 0x00 0x03 0x00 + --ex: 0x09 0x03 0x61 0x10 0x00 0x6C 0x50 0x00 0x00 0x10 0x36 0x00 0x49 0x00 0x36 0x00 + --ex: 0x09 0x03 0x65 0x10 0x00 0x0C 0x51 0x00 0x00 0x10 0x00 0x00 0xF4 0x00 0x2E 0x00 + -- MenuLSB MenuMSB line Type TextID NextLSB NextMSB Val_Min Val_Max Val_Def + + local ctx = DSM_Context + local i = multiBuffer(14) + local type = multiBuffer(15) + local line = ctx.MenuLines[i] + + -- are we trying to override existing line + if (line.Type > 0 and type == 0) then + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: ERROR. Trying to ZERO Override: %s\n", menuLib.menuLine2String(line)) end + return ctx.MenuLines[ctx.CurLine] + end + + ctx.CurLine = i + + line.lineNum = i + line.MenuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + line.Type = type + line.TextId = Dsm_to_Int16(multiBuffer(16), multiBuffer(17)) + line.Text = nil -- Fill at Post processing + line.ValId = Dsm_to_Int16(multiBuffer(18), multiBuffer(19)) + + -- Singed int values + line.Min = Dsm_to_SInt16(multiBuffer(20), multiBuffer(21)) + line.Max = Dsm_to_SInt16(multiBuffer(22), multiBuffer(23)) + line.Def = Dsm_to_SInt16(multiBuffer(24), multiBuffer(25)) + + line.Val=nil + + menuLib.MenuLinePostProcessing(line) + + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuLine: %s\n", menuLib.menuLine2String(line)) end + + if (line.MenuId~=ctx.Menu.MenuId) then + -- Going Back too fast: Stil receiving lines from previous menu + ctx.Menu.MenuId = line.MenuId + Log.LOG_write("WARNING: Overriding current Menu from Line\n") + end + + return line +end + +local function DSM_parseMenuValue() + --ex: 0x09 0x04 0x53 0x10 0x00 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + --ex: 0x09 0x04 0x61 0x10 0x02 0x10 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + -- MenuLSB MenuMSB ValLSB ValMSB V_LSB V_MSB + + -- Identify the line and update the value + local ctx = DSM_Context + local menuId = Dsm_to_Int16(multiBuffer(12), multiBuffer(13)) + local valId = Dsm_to_Int16(multiBuffer(14), multiBuffer(15)) + local value = Dsm_to_SInt16(multiBuffer(16), multiBuffer(17)) --Signed int + + local updatedLine = nil + for i = 0, MAX_MENU_LINES do -- Find the menu line for this value + local line = ctx.MenuLines[i] + if line ~= nil and line.Type ~= 0 then + if line.Type ~= LINE_TYPE.MENU and line.ValId == valId then -- identifier of ValueId stored in the line + line.Val = value + ctx.CurLine = i + updatedLine = line + break + end + end + end + + if (updatedLine == nil) then + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: ERROR, Cant find Menu Line with MenuId=%X, ValID=%X to update\n", menuId, valId) end + else + if (DEBUG_ON) then Log.LOG_write("RESPONSE MenuValue: UPDATED: %s\n", menuLib.menuLine2String(updatedLine)) + end + end + return updatedLine ~= nil +end + +local function DSM_parseReqTxInfo() + local portNo = multiBuffer(12) + TxInfo_Type = multiBuffer(13) + if (DEBUG_ON) then Log.LOG_write("RESPONSE ReqTXChannelInfo(#%d %s InfoType=0x%0X)\n", + portNo, MODEL.PORT_TEXT[portNo], TxInfo_Type) end + + TxInfo_Step = 0 + + return portNo +end + +------------------------------------------------------------------------------------------------------------ +local function DSM_processResponse() + local ctx = DSM_Context + local cmd = multiBuffer(11) -- Response Command + + if (DEBUG_ON > 1) then Log.LOG_write("%s: RESPONSE %s \n", menuLib.phase2String(ctx.Phase), multiBuffer2String()) end + if (DEBUG_ON and cmd > 0x00) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + + if cmd == 0x01 then -- read version + DSM_parseRxVersion() + --Lib.Init_Text(DSM_Context.RX.Id) + ctx.isReset = false -- no longer resetting + ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId = 0 + + elseif cmd == 0x02 then -- read menu title + local menu = DSM_parseMenu() + + -- Update Selected Line navigation + if menu.NextId ~= 0 then + ctx.SelLine = NEXT_BUTTON -- highlight Next + else + ctx.SelLine = BACK_BUTTON -- highlight Back + end + + if (ctx.Menu.MenuId == 0x0001) then -- Still in RESETTING MENU??? + -- Star from Start + if (DEBUG_ON) then Log.LOG_write("RX Reset: Still not done, restart again!!!\n") end + ctx.Menu.MenuId = 0 + ctx.Phase = PHASE.RX_VERSION + else + ctx.Phase = PHASE.MENU_LINES + end + + + elseif cmd == 0x03 then -- menu lines + local line = DSM_parseMenuLine() + + -- Update Selected line navigation + if (ctx.SelLine == BACK_BUTTON or ctx.SelLine == NEXT_BUTTON or ctx.SelLine == PREV_BUTTON) + and menuLib.isSelectableLine(line) then -- Auto select the current line + ctx.SelLine = line.lineNum + end + + ctx.Phase = PHASE.MENU_LINES + + elseif cmd == 0x04 then -- read menu values + if DSM_parseMenuValue() then + ctx.Phase = PHASE.MENU_VALUES + else + ctx.Phase = PHASE.WAIT_CMD + end + + elseif cmd == 0x05 then -- Request TX Info + local portNo = DSM_parseReqTxInfo() + ctx.CurLine = portNo + ctx.Phase = PHASE.MENU_REQ_TX_INFO + + elseif cmd == 0xA7 then -- answer to EXIT command + if (DEBUG_ON) then Log.LOG_write("RESPONSE RX Exit\n") end + if (ctx.Phase==PHASE.EXIT) then -- Expected RX Exit + ctx.Phase = PHASE.EXIT_DONE + else -- UnExpected RX Exit + DSM_ReleaseConnection() + error("RX Connection Drop") + end + + elseif cmd == 0x00 then -- NULL response (or RX heartbeat) + -- 09 00 01 00 00 00 00 00 00 00 00 00 00 00 00 + -- 09 00 7E 00 20 9E 28 00 20 9E 28 00 20 8D 7E : After TX Heartbeat one of this (FC6250) + -- 09 00 18 00 20 08 00 00 00 08 00 00 00 98 AE AR8360T + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RESPONSE RX Heartbeat --Context: 0x%02X\n", + menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase), multiBuffer(12)) end + else + if (DEBUG_ON) then Log.LOG_write("RESPONSE Unknown Command (0x%X) DATA=%s\n", cmd, multiBuffer2String()) end + end + + return cmd +end + +------------------------------------------------------------------------------------------------------------ +local function DSM_Send_Receive() + local ctx = DSM_Context + + -- Receive part: Process incoming messages if there is nothing to send + if ctx.SendDataToRX == 0 and multiBuffer(10) == 0x09 then + local cmd = DSM_processResponse() + + multiBuffer(10, 0x00) -- Clear Response Buffer to know that we are done with the response + RXInactivityTime = getTime() + SEND_TIMEOUT*4 -- Reset RX Inactivity timeout + + if (cmd > 0x00) then -- RX HeartBeat ?? + -- Only change to SEND mode if we received a valid response (Ignore heartbeat) + ctx.SendDataToRX = 1 + ctx.Refresh_Display = true + end + else + if (getTime() > RXInactivityTime and ctx.Phase ~= PHASE.RX_VERSION and ctx.Phase ~= PHASE.EXIT_DONE) then + if (ctx.isEditing()) then -- If Editing, Extend Timeout + RXInactivityTime = getTime() + SEND_TIMEOUT*4 + else + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: RX INACTIVITY TIMEOUT\n", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + DSM_ReleaseConnection() + error("RX Disconnected") + end + end + end + + -----TX Part -------------------------------------- + if ctx.SendDataToRX == 1 then -- Need to send a request + ctx.SendDataToRX = 0 + DSM_sendRequest() + TXInactivityTime = getTime() + SEND_TIMEOUT -- Reset Inactivity timeout + else + -- Check if enouth time has passed from last transmit/receive activity + if getTime() > TXInactivityTime then + ctx.SendDataToRX = 1 -- Switch to Send mode to send heartbeat + ctx.Refresh_Display = true + + -- Only change to WAIT_CMD if we are NOT wating for RX version + if ctx.Phase ~= PHASE.RX_VERSION then + -- Phase = If IsEditing then VALUE_CHANGING_WAIT else WAIT_CMD + ctx.Phase = (ctx.isEditing() and PHASE.VALUE_CHANGING_WAIT) or PHASE.WAIT_CMD + end + end + end +end + +-- Init +local function DSM_Init(toolName) + local dateTime = getDateTime() + local dateStr = dateTime.year.."-"..dateTime.mon.."-"..dateTime.day.." "..dateTime.hour..":"..dateTime.min + + local ver, radio, maj, minor, rev, osname = getVersion() + + if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil + + IS_EDGETX = string.sub(osname,1,1) == 'E' + + if (DEBUG_ON) then + Log.LOG_write("---------------DSM New Session %s ----------------\n", toolName, dateStr) + Log.LOG_write("Radio Info: %s\n", radio .. " " .. (osname or "OpenTx") .. " " .. ver) + Log.LOG_write("Date : %s\n", dateStr) + Log.LOG_write("DsmLib Version : %s\n", LIB_VERSION) + end +end + +local function DSM_Init_Text_Exceptions() + -- Apply special restrictions to some Values + + local function getTxChText(ch) + return " ("..(MODEL.TX_CH_TEXT[ch] or "--")..")" + end + + local List_Values = menuLib.List_Values + local List_Text = menuLib.List_Text + local Text = menuLib.Text + + Log.LOG_write("Initializing TEXT Exception\n") + + -- Channel selection for SAFE MODE and GAINS on FC6250HX + --List_Text[0x000C] = "Inhibit?" --? + for i = 0, 7 do + List_Text[0x000D + i] = "Ch"..(i+5) ..getTxChText(i+4) + end -- Aux channels (Ch5 and Greater) + + -- Servo Output values.. + local servoOutputValues = {0x0003,0x002D,0x002E,0x002F} --Inh (GAP), 5.5ms, 11ms, 22ms. Fixing L_m1 with 0..244 range! + --List_Text[0x002D] = "5.5ms" + --[0x002E] = "11ms" + --List_Text[0x002F] = "22ms" + + -- Gain Values + local gainValues = {0x0032,0x0033,0x0034} -- 1X, 2X, 4X -- Fixing L_m1 with 0..244 range! + --List_Text[0x0032] = "1 X" + --[0x0033] = "2 X" + -- List_Text[0x0034] = "4 X" + + -- List of Channels for Safe, Gains, Panic, except FC6250HX that uses other range (0x00C..0x015) + -- the valid range Starts with GEAR if enabled (Thr,Ail,Ele,Rud are not valid, the RX reject them ) + -- Valid Values: Inhibit? (GAP), Gear,Aux1..Aux7,X-Plus-1..XPlus-8 + local channelValues = {0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049} + + --List_Text[0x0035] = "Inhibit?" + for i = 0, 11 do + List_Text[0x0036 + i] = "Ch"..(i+1) .. getTxChText(i) + end -- Channels on AR637T + + for i = 1, 8 do -- 41..49 + List_Text[0x0041 + i] = "Ch"..(i+12) + end + + -- Flight mode channel selection + --Text[0x0078] = "FM Channel" + List_Values[0x0078]=channelValues + + -- Gain channel selection + --Text[0x0089] = "Gain Channel" + List_Values[0x0089]=channelValues + + -- Gain Sensitivity selection + --Text[0x008A] = "Gain Sensitivity/r"; + List_Values[0x008A]=gainValues -- Right Alight, (L_M1 was wide open range 0->244) + + -- Safe mode options, Ihnibit + this values + local safeModeOptions = {0x0003,0x00B0,0x00B1} -- inh (gap), "Self-Level/Angle Dem, Envelope + --List_Text[0x00B0] = "Self-Level/Angle Dem" + --List_Text[0x00B1] = "Envelope" + + --Text[0x00D2] = "Panic Channel" + List_Values[0x00D2]=channelValues + + --Inh, Self-Level/Angle Dem, Envelope -- (L_M was wide open range 0->244) + --Text[0x01F8] = "Safe Mode"; + List_Values[0x01F8]=safeModeOptions +end + +-- Initial Setup +local function FP_Init(toolname) + DSM_Context.Phase = PHASE.INIT + + DSM_Init(toolname) + menuLib.clearAllText() +end + +local initStep=0 +local FileState = {} + +local function Message_Init() + lcd.clear() + if (initStep == 0) then + if (IS_EDGETX) then + -- Load all messages at once + menuLib.LoadTextFromFile(MSG_FILE,13) + initStep=1 + + else + -- load messages incrementally to avoid "CPU Limit" + lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0)) + if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then + initStep=1 + end + end + elseif (initStep == 1) then + DSM_Init_Text_Exceptions() + + DSM_Context.Phase = PHASE.RX_VERSION + DSM_StartConnection() + end +end + +local function FP_Run() + if (DSM_Context.Phase==PHASE.INIT) then + Message_Init() + return 0 + end + + return DSM_Send_Receive() +end + +local function FP_Done() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.EXIT_DONE + DSM_ReleaseConnection() +end + +return { init=FP_Init, run=FP_Run, done=FP_Done } diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmLogLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmLogLib.lua new file mode 100644 index 0000000..4d13be2 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmLogLib.lua @@ -0,0 +1,33 @@ +local LogLib = { } + +local LOG_FILE = "/LOGS/dsm_log.txt" +local logFile = nil +local logCount=0 + +function LogLib.LOG_open() + logFile = io.open(LOG_FILE, "w") -- Truncate Log File +end + +function LogLib.LOG_write(...) + if (logFile==nil) then LogLib.LOG_open() end + local str = string.format(...) + + if (str==nil) then return end + + io.write(logFile, str) + + str = string.gsub(str,"\n"," ") -- Elimitate return from line, since print will do it + print(str) + + if (logCount > 10) then -- Close an re-open the file + io.close(logFile) + logFile = io.open(LOG_FILE, "a") + logCount =0 + end +end + +function LogLib.LOG_close() + if (logFile~=nil) then io.close(logFile) end +end + +return LogLib diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P1.lua b/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P1.lua new file mode 100644 index 0000000..b228bd5 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P1.lua @@ -0,0 +1,167 @@ +local MODEL, M_DATA, LOG_write = ... + +--[[ +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + hashName = "", + modelOutputChannel = {}, -- Output information from OTX/ETX + + TX_CH_TEXT= { [0]=""}, + PORT_TEXT = { [0]=""}, + + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script + } + + -- MENU DATA Management +local M_DATA = {} -- Store the variables used in the Menus. + +--]] + +local DATA_PATH = "/MODELS/DSMDATA" +local TX_CHANNELS = 12 + +local MV_DATA_END = 1040 + + + local function hashName(mName) + local c=10000; + + local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_" + prefix = string.gsub(prefix,"% ","_") -- Change any space to "_" + prefix = string.sub(prefix,1,5) -- Take the first 5 characters + + -- Simple Hash of the Model Name adding each character + for i = 1, #mName do + local ch = string.byte(mName,i,i) + c=c+ch + end + + return (prefix .. c) -- Return Prefix + Hash + end + + -- Load Menu Data from a file + local function ST_LoadFileData() + local fname = hashName(MODEL.modelName)..".txt" + MODEL.hashName = fname + + -- Clear Menu Data + for i = 0, MV_DATA_END do + M_DATA[i]=nil + end + + print("Loading File:"..fname) + + local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File + -- cannot read file??? + if (dataFile==nil) then return 0 end + + local line = io.read(dataFile, 5000) + io.close(dataFile) + + if #line == 0 then return 0 end -- No data?? + + -- Process the input, each line is "Var_Id : Value" format + -- Store it into MANU_DATA + local i=0 + for k, v in string.gmatch(line, "(%d+):(%d+)") do + M_DATA[k+0]=v+0 -- do aritmentic to convert string to number + i=i+1 + end + + -- Return 0 if no lines processed, 1 otherwise + if (i > 0) then return 1 else return 0 end + end + + local function getModuleChannelOrder(num) + --Determine fist 4 channels order + local ch_n={} + local st_n = {[0]= "R", "E", "T", "A" } + local c_ord=num -- ch order + if (c_ord == -1) then + ch_n[0] = st_n[3] + ch_n[1] = st_n[1] + ch_n[2] = st_n[2] + ch_n[3] = st_n[0] + else + ch_n[bit32.band(c_ord,3)] = st_n[3] + c_ord = math.floor(c_ord/4) + ch_n[bit32.band(c_ord,3)] = st_n[1] + c_ord = math.floor(c_ord/4) + ch_n[bit32.band(c_ord,3)] = st_n[2] + c_ord = math.floor(c_ord/4) + ch_n[bit32.band(c_ord,3)] = st_n[0] + end + + local s = "" + for i=0,3 do + s=s..ch_n[i] + end + return s + end + + local function ReadTxModelData() + local TRANSLATE_AETR_TO_TAER=false + local table = model.getInfo() -- Get the model name + MODEL.modelName = table.name + + local module = model.getModule(0) -- Internal + if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External + if (module~=nil) then + if (module.Type==6 ) then -- MULTI-MODULE + local chOrder = module.channelsOrder + local s = getModuleChannelOrder(chOrder) + LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s) + + if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true + else TRANSLATE_AETR_TO_TAER=false + end + end + end + + -- Read Ch1 to Ch10 + local i= 0 + for i = 0, TX_CHANNELS-1 do + local ch = model.getOutput(i) -- Zero base + if (ch~=nil) then + MODEL.modelOutputChannel[i] = ch + if (string.len(ch.name)==0) then + ch.formatCh = string.format("TX:Ch%i",i+1) + else + ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--") + end + end + end + + -- Translate AETR to TAER + + if (TRANSLATE_AETR_TO_TAER) then + LOG_write("Applying AETR -> TAER translation\n") + local ail = MODEL.modelOutputChannel[0] + local elv = MODEL.modelOutputChannel[1] + local thr = MODEL.modelOutputChannel[2] + + MODEL.modelOutputChannel[0] = thr + MODEL.modelOutputChannel[1] = ail + MODEL.modelOutputChannel[2] = elv + end + + -- Create the Port Text to be used + LOG_write("Ports/Channels:\n") + for i = 0, TX_CHANNELS-1 do + local ch = MODEL.modelOutputChannel[i] + if (ch~=nil) then + MODEL.TX_CH_TEXT[i] = ch.formatCh + MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i]) + LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical) + end + end + end + + -- Main Program + + LOG_write("Reading Model Info\n") + ReadTxModelData() + local r = ST_LoadFileData() + return r + + diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P2.lua b/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P2.lua new file mode 100644 index 0000000..6897b31 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmMIN_P2.lua @@ -0,0 +1,282 @@ +local MODEL, M_DATA, LOG_write = ... + +--[[ +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + hashName = "", + modelOutputChannel = {}, -- Output information from OTX/ETX + + TX_CH_TEXT= { [0]=""}, + PORT_TEXT = { [0]=""}, + + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script + } + + -- MENU DATA Management +local M_DATA = {} -- Store the variables used in the Menus. + +--]] + + +local TX_CHANNELS = 12 + +local AT_PLANE = 0 + +local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"} + +--[[ +local WT_A1 = 0 +local WT_A2 = 1 +local WT_FLPR = 2 +local WT_A1_F1 = 3 +local WT_A2_F1 = 4 +local WT_A2_F2 = 5 +--]] +local WT_ELEVON_A = 6 +local WT_ELEVON_B = 7 + +local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"} + +--[[ +local TT_R1 = 0 +local TT_R1_E1 = 1 +local TT_R1_E2 = 2 +local TT_R2_E1 = 3 +local TT_R2_E2 = 4 +--]] + +local TT_VT_A = 5 +local TT_VT_B = 6 +local TT_TLRN_A = 7 +local TT_TLRN_B = 8 +local TT_TLRN_A_R2 = 9 +local TT_TLRN_B_R2 = 10 + +local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele", + "VTail A","VTail B","Taileron A","Taileron B","Taileron A + Dual Rud","Taileron B + Dual Rud"} + + +local MV_AIRCRAFT_TYPE = 1001 +local MV_WING_TYPE = 1002 +local MV_TAIL_TYPE = 1003 + +local MV_CH_BASE = 1010 +local MV_CH_THR = 1010 +local MV_CH_L_AIL = 1011 +local MV_CH_R_AIL = 1012 +local MV_CH_L_FLP = 1013 +local MV_CH_R_FLP = 1014 + +local MV_CH_L_RUD = 1015 +local MV_CH_R_RUD = 1016 +local MV_CH_L_ELE = 1017 +local MV_CH_R_ELE = 1018 + +local MV_PORT_BASE = 1020 + +local MV_DATA_END = 1040 + +--Channel Types -- +local CT_NONE = 0x00 +local CT_AIL = 0x01 +local CT_ELE = 0x02 +local CT_RUD = 0x04 +local CT_REVERSE = 0x20 +local CT_THR = 0x40 +local CT_SLAVE = 0x80 + +-- Seems like Reverse Mix is complement of the 3 bits +local CMT_NORM = 0x00 -- 0000 +local CMT_AIL = 0x10 -- 0001 Taileron +local CMT_ELE = 0x20 -- 0010 For VTIAL and Delta-ELEVON +local CMT_RUD = 0x30 -- 0011 For VTIAL +local CMT_RUD_REV = 0x40 -- 0100 For VTIAL +local CMT_ELE_REV = 0x50 -- 0101 For VTIAL and Delta-ELEVON A +local CMT_AIL_REV = 0x60 -- 0110 Taileron +local CMT_NORM_REV = 0x70 -- 0111 + +local MT_NORMAL = 0 +local MT_REVERSE = 1 + +local function channelType2String(byte1, byte2) + local s = "" + + if (byte2==0) then return s end; + + if (bit32.band(byte2,CT_AIL)>0) then s=s.."Ail" end + if (bit32.band(byte2,CT_ELE)>0) then s=s.."Ele" end + if (bit32.band(byte2,CT_RUD)>0) then s=s.."Rud" end + if (bit32.band(byte2,CT_THR)>0) then s=s.."Thr" end + + if (bit32.band(byte2,CT_REVERSE)>0) then s=s.."-" end + + if (bit32.band(byte2,CT_SLAVE)>0) then s=s.." Slv" end + + if (byte1==CMT_NORM) then s=s.." " + elseif (byte1==CMT_AIL) then s=s.." M_Ail" + elseif (byte1==CMT_ELE) then s=s.." M_Ele" + elseif (byte1==CMT_RUD) then s=s.." M_Rud" + elseif (byte1==CMT_RUD_REV) then s=s.." M_Rud-" + elseif (byte1==CMT_ELE_REV) then s=s.." M_Ele-" + elseif (byte1==CMT_AIL_REV) then s=s.." M_Ail-" + elseif (byte1==CMT_NORM_REV) then s=s.." M-" + end + + return s; + end + + -- This Creates the Servo Settings that will be used to pass to +-- Forward programming +local function CreateDSMPortChannelInfo() + local function ApplyWingMixA(b2) + -- ELEVON + if (b2==CT_AIL+CT_ELE) then return CMT_ELE end; -- 0x03 + if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83 + end + + local function ApplyWingMixB(b2) + -- ELEVON + if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03 + if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x83 + end + + local function ApplyTailMixA(b2) + -- VTAIL + -- Default normal/reverse behaviour + if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06 + if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_ELE end; -- 0x86 + + --TAILERON + -- Default normal/reverse behaviour + if (b2==CT_AIL+CT_ELE) then return CMT_NORM end; -- 0x03 + if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_AIL end; -- 0x83 + end + + local function ApplyTailMixB(b2) + -- VTAIL + -- Default normal/reverse behaviour + if (b2==CT_RUD+CT_ELE) then return CMT_NORM end; -- 0x06 + if (b2==CT_RUD+CT_ELE+CT_SLAVE) then return CMT_RUD end; -- 0x86 + + --TAILERON + if (b2==CT_AIL+CT_ELE) then return CMT_AIL end; -- 0x03 + if (b2==CT_AIL+CT_ELE+CT_SLAVE) then return CMT_NORM end; -- 0x83 + end + + local function reverseMix(b) + if (b==CMT_NORM) then return CMT_NORM_REV end; + if (b==CMT_AIL) then return CMT_AIL_REV end; + if (b==CMT_ELE) then return CMT_ELE_REV end; + if (b==CMT_RUD) then return CMT_RUD_REV end; + return b + end + + local DSM_Ch = MODEL.DSM_ChannelInfo + + for i=0, TX_CHANNELS-1 do + DSM_Ch[i] = {[0]= CMT_NORM, CT_NONE, nil} -- Initialize with no special function + end + + --local aircraftType = M_DATA[MV_AIRCRAFT_TYPE] + local wingType = M_DATA[MV_WING_TYPE] + local tailType = M_DATA[MV_TAIL_TYPE] + + local thrCh = M_DATA[MV_CH_THR] + local lAilCh = M_DATA[MV_CH_L_AIL] + local rAilCh = M_DATA[MV_CH_R_AIL] + + local lElevCh = M_DATA[MV_CH_L_ELE] + local rElevCh = M_DATA[MV_CH_R_ELE] + + local lRudCh = M_DATA[MV_CH_L_RUD] + local rRudCh = M_DATA[MV_CH_R_RUD] + + -- Channels in menu vars are Zero base, Channel info is 1 based + + -- THR + if (thrCh~=nil and thrCh < 10) then DSM_Ch[thrCh][1]= CT_THR end + + -- AIL (Left and Right) + if (lAilCh~=nil) then DSM_Ch[lAilCh][1] = CT_AIL end + if (rAilCh~=nil) then DSM_Ch[rAilCh][1] = CT_AIL+CT_SLAVE end + -- ELE (Left and Right) + if (lElevCh~=nil) then DSM_Ch[lElevCh][1] = CT_ELE end + if (rElevCh~=nil) then DSM_Ch[rElevCh][1] = CT_ELE+CT_SLAVE end + -- RUD (Left and Right) + if (lRudCh~=nil) then DSM_Ch[lRudCh][1] = CT_RUD end + if (rRudCh~=nil) then DSM_Ch[rRudCh][1] = CT_RUD+CT_SLAVE end + + -- VTAIL: RUD + ELE + if (tailType==TT_VT_A) then + DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE + DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE + elseif (tailType==TT_VT_B) then + DSM_Ch[lElevCh][1] = CT_RUD+CT_ELE+CT_SLAVE + DSM_Ch[rElevCh][1] = CT_RUD+CT_ELE + end + + -- TAILERRON: 2-ELE + AIL + if (tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then + DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE + DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE + elseif (tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then + DSM_Ch[lElevCh][1] = CT_AIL+CT_ELE+CT_SLAVE + DSM_Ch[rElevCh][1] = CT_AIL+CT_ELE + end + + ---- ELEVON : AIL + ELE + if (wingType==WT_ELEVON_A) then + DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE + DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE + elseif (wingType==WT_ELEVON_B) then + DSM_Ch[lAilCh][1] = CT_AIL+CT_ELE+CT_SLAVE + DSM_Ch[rAilCh][1] = CT_AIL+CT_ELE + end + + ------MIXES --------- + + -- TAIL Mixes (Elevator and VTail) + if (tailType==TT_VT_A or tailType==TT_TLRN_A or tailType==TT_TLRN_A_R2) then + DSM_Ch[lElevCh][0] = ApplyTailMixA(DSM_Ch[lElevCh][1]) + DSM_Ch[rElevCh][0] = ApplyTailMixA(DSM_Ch[rElevCh][1]) + elseif (tailType==TT_VT_B or tailType==TT_TLRN_B or tailType==TT_TLRN_B_R2) then + DSM_Ch[lElevCh][0] = ApplyTailMixB(DSM_Ch[lElevCh][1]) + DSM_Ch[rElevCh][0] = ApplyTailMixB(DSM_Ch[rElevCh][1]) + end + + ---- ELEVON : AIL + ELE + if (wingType==WT_ELEVON_A) then + DSM_Ch[lAilCh][0] = ApplyWingMixA(DSM_Ch[lAilCh][1]) + DSM_Ch[rAilCh][0] = ApplyWingMixA(DSM_Ch[rAilCh][1]) + elseif (wingType==WT_ELEVON_B) then + DSM_Ch[lAilCh][0] = ApplyWingMixB(DSM_Ch[lAilCh][1]) + DSM_Ch[rAilCh][0] = ApplyWingMixB(DSM_Ch[rAilCh][1]) + end + + -- Apply Gyro Reverse as needed for each channel as long as it is used + for i=0, TX_CHANNELS-1 do + if (M_DATA[MV_PORT_BASE+i]==MT_REVERSE and DSM_Ch[i][1]>0) then + DSM_Ch[i][0]=reverseMix(DSM_Ch[i][0]) + DSM_Ch[i][1]=DSM_Ch[i][1]+CT_REVERSE + end + end + + -- Show how it looks + for i=0, 9 do + local b1,b2 = DSM_Ch[i][0], DSM_Ch[i][1] + local s1 = channelType2String(b1,b2) + local s = string.format("%s (%02X %02X) %s\n", MODEL.PORT_TEXT[i], + b1, b2,s1) + DSM_Ch[i][2]=s1 + LOG_write(s) + end + + --MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType]) +end + + -- Main Program + + LOG_write("Creating DSMPort Info\n") + CreateDSMPortChannelInfo() + + diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmMainMenuLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmMainMenuLib.lua new file mode 100644 index 0000000..f23bac3 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmMainMenuLib.lua @@ -0,0 +1,90 @@ +local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters +local MAIN_MENU_LIB_VERSION = "0.56" +local MODEL = modelLib.MODEL + +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE + +local lastGoodMenu=0 + +-- Creates the menus to Render with the GUI +local function ST_LoadMenu(menuId) + local ctx = menuLib.DSM_Context + menuLib.clearMenuLines() + + if (menuId==0x1000) then -- MAIN MENU + ctx.Menu = { MenuId = 0x1000, Text = "Main Menu ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Model Setup", ValId = 0xFFF3,TextId=0 } + + if (SIMULATION_ON) then + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text = "RX Simulator (GUI dev only)", ValId = 0xFFF1, TextId=0 } -- Menu 0xFFF2 to SIMULATOR + end + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "Forward Programming RX", ValId = 0xFFF2, TextId=0 } -- Menu 0xFFF2 to Real RX + ctx.SelLine = 6 + + lastGoodMenu = menuId + else + --print("NOT IMPLEMENTED") + ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = menuLib.BACK_BUTTON + end + + menuLib.PostProcessMenu() +end + +local function Main_Send_Receive() + local ctx = menuLib.DSM_Context + + if ctx.Phase == PHASE.RX_VERSION then -- Just Init RX Version + ctx.RX.Name = "Main Menu" + ctx.RX.Version = MAIN_MENU_LIB_VERSION + ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId = 0 + + ctx.Refresh_Display = true + elseif ctx.Phase == PHASE.WAIT_CMD then + + elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title + if ctx.Menu.MenuId == 0 then -- First time loading a menu ? + ST_LoadMenu(0x01000) + else + ST_LoadMenu(ctx.Menu.MenuId) + end + ctx.Phase = PHASE.WAIT_CMD + ctx.Refresh_Display = true + + elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + --if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + --if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + + elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then + local line = ctx.MenuLines[ctx.SelLine] + + elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + --if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + --if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + --if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + ctx.Phase = PHASE.WAIT_CMD + + elseif ctx.Phase == PHASE.EXIT then + ctx.Phase=PHASE.EXIT_DONE + return 1 + end + + return 0 +end + +local function Main_Init() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.RX_VERSION +end + +local function Main_Done() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.EXIT_DONE +end + +return { init=Main_Init, run=Main_Send_Receive, done=Main_Done } \ No newline at end of file diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmMenuLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmMenuLib.lua new file mode 100644 index 0000000..3831b60 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmMenuLib.lua @@ -0,0 +1,788 @@ +--- ######################################################################### +---- # # +---- # Copyright (C) OpenTX/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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- This script library is a rewrite of the original DSM forward programming Lua +-- Script. The goal is to make it easier to understand, mantain, and to +-- separate the GUI from the DSM Forward programming engine/logic +-- in this way, GUIs can evolve independent. OpenTX Gui, EdgeTx GUI, Small Radios, etc. + +-- Code is based on the code/work by: Pascal Langer (Author of the Multi-Module) +-- Rewrite/Enhancements By: Francisco Arzu + +local Log, DEBUG_ON = ... -- Parameters + + +local MenuLib = { } + +local PHASE = { + INIT = 0, + RX_VERSION = 1, + WAIT_CMD = 2, + MENU_TITLE = 3, + MENU_REQ_TX_INFO = 4, + MENU_LINES = 5, + MENU_VALUES = 6, + VALUE_CHANGING = 7, + VALUE_CHANGING_WAIT = 8, + VALUE_CHANGE_END = 9, + EXIT = 10, + EXIT_DONE = 11 +} + +local LINE_TYPE = { + MENU = 0x1C, + LIST_MENU = 0x0C, -- List: INC Change + Validate + LIST_MENU_NC = 0x6C, -- List: No Incremental Change + LIST_MENU_NC2 = 0x6D, -- List: No Incremental Change (Frame Rate Herz) + LIST_MENU_TOG = 0x4C, -- List: Incremental Change, sometimes bolean/Toggle menu (if only 2 values) + LIST_MENU_ORI = 0xCC, -- List: Incremental Change, Orientation Heli + + VALUE_NUM_I8_NC = 0x60, -- 8 bit number, no incremental change + VALUE_PERCENT = 0xC0, -- 8 bit number, Signed, percent + VALUE_DEGREES = 0xE0, -- 8 bit number, Signed, Degress + VALUE_NUM_I8 = 0x40, -- 8 bit number + VALUE_NUM_I16 = 0x41, -- 16 Bit number + VALUE_NUM_SI16 = 0xC1, -- 16 bit number, Signed + + LT_EMPTY = 0x00 +} + +-- Bug in Lua compiler, confusing with global BOLD and RIGHT +local DISP_ATTR = { + _BOLD = 0x01, _RIGHT=0x02, _CENTER=0x04, PERCENT = 0x10, DEGREES=0x20, FORCED_MENU = 0x40 +} + +--RX IDs-- +local RX = { + AR636B = 0x0001, + SPM4651T = 0x0014, + AR637T = 0x0015, + AR637TA = 0x0016, + FC6250HX = 0x0018, + AR630 = 0x0019, + AR8360T = 0x001A, + AR10360T = 0x001C, + AR631 = 0x001E +} + +local DSM_Context = { + Phase = PHASE.INIT, + Menu = { MenuId = 0, Text = "", TextId = 0, PrevId = 0, NextId = 0, BackId = 0 }, + MenuLines = {}, + RX = { Id=0, Name = "", Version = "" }, + Refresh_Display = true, + SendDataToRX = 1, + + SelLine = 0, -- Current Selected Line + EditLine = nil, -- Current Editing Line + CurLine = -1, -- Current Line Requested/Parsed via h message protocol + isReset = false -- false when starting from scracts, true when starting from Reset +} + +function DSM_Context.isEditing() return DSM_Context.EditLine~=nil end + +local MAX_MENU_LINES = 6 +local BACK_BUTTON = -1 -- Tread it as a display line #-1 +local NEXT_BUTTON = MAX_MENU_LINES + 1 -- Tread it as a display line #7 +local PREV_BUTTON = MAX_MENU_LINES + 2 -- Tread it as a display line #7 + +-- Text Arrays for Display Text and Debuging +local PhaseText = {} +local LineTypeText = {} + +local Text = {} -- Text for Menu and Menu Lines (Headers only) +local List_Text = {} -- Messages for List Options (values only) +local List_Text_Img = {} -- If the Text has Attached Images +local List_Values = {} -- Additiona restrictions on List Values when non contiguos (L_M1 lines has this problem) +local Flight_Mode = {[0]="Fligh Mode"} +local RxName = {} + +local StartTime = 0 + +------------------------------------------------------------------------------------------------------------ +-- Get Elapsed Time since we started running the Script. Return a float in format: Seconds.Milliseconds +function MenuLib.getElapsedTime() + local t = getTime() + if (StartTime == 0) then StartTime = t end + + return ((t - StartTime) * 10) / 1000 +end + +------------- Line Type helper functions ------------------------------------------------------------------ + +-- Check if the text are Flight modes, who will be treated different for Display +function MenuLib.isFlightModeLine(line) + return (line.TextId >= 0x8000 and line.TextId <= 0x8003) +end + +function MenuLib.isSelectableLine(line) -- is the display line Selectable?? + -- values who are not selectable + if (line.Type == 0) then return false end -- Empty Line + if (line.Type == LINE_TYPE.MENU and line.ValId == line.MenuId and bit32.band(line.TextAttr, DISP_ATTR.FORCED_MENU)==0) then return false end -- Menu that navigates to Itself? + if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display + if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Selectable + return true +end + +function MenuLib.isEditableLine(line) -- is the display line editable?? + -- values who are not editable + if (line.Type == 0 or line.Type == LINE_TYPE.MENU) then return false end -- Menus are not editable + if (line.Min==0 and line.Max==0 and line.Def==0) then return false end -- Values with no Range are only for display + if (line.Type == LINE_TYPE.VALUE_NUM_I8_NC and MenuLib.isFlightModeLine(line)) then return false end -- Flight mode is not Editable + -- any other is Editable + return true +end + +function MenuLib.isListLine(line) -- is it a List of options?? + if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU or + line.Type == LINE_TYPE.LIST_MENU_TOG or line.Type == LINE_TYPE.LIST_MENU_NC2 or + line.Type == LINE_TYPE.LIST_MENU_ORI) then return true end + return false +end + +function MenuLib.isPercentValueLineByMinMax(line) + return + (line.Min == 0 and line.Max == 100) or ( line.Min == -100 and line.Max == 100) or + ( line.Min == 0 and line.Max == 150) or ( line.Min == -150 and line.Max == 150) +end + +function MenuLib.isPercentValueLine(line) -- is it a Percent value?? + if (line.Type == LINE_TYPE.VALUE_PERCENT) then return true end + return false +end + +function MenuLib.isNumberValueLine(line) -- is it a number ?? + if (MenuLib.isListLine(line) or line.Type == LINE_TYPE.MENU or line.Type == 0) then return false + else return true end +end + +function MenuLib.isIncrementalValueUpdate(line) + if (line.Type == LINE_TYPE.LIST_MENU_NC or line.Type == LINE_TYPE.LIST_MENU_NC2 or + line.Type == LINE_TYPE.VALUE_NUM_I8_NC or line.Type == LINE_TYPE.VALUE_DEGREES) then return false end + return true +end + +------------------------------------------------------------------------------------------------------------ +function MenuLib.Get_Text(index) + if (index >= 0x8000) then + return Flight_Mode[0] + end + + local out = Text[index] -- Find in regular header first + if out== nil then + out = List_Text[index] -- Try list values, don't think is necesary, but just playing Safe + end + if out == nil then -- unknown... + out = "Unknown_" .. string.format("%X", index) + end + return out +end + +function MenuLib.Get_List_Text(index) + local out = List_Text[index] -- Try to find the message in List_Text + if out == nil then + out = Text[index] -- Try list headers, don't think is necesary, but just playing Safe + end + if out == nil then -- unknown... + out = "UnknownLT_" .. string.format("%X", index) + end + return out +end + +function MenuLib.Get_List_Text_Img(index) + local out = List_Text_Img[index] + return out +end + +function MenuLib.Get_List_Values(index) + local out = List_Values[index] + return out +end + +function MenuLib.Get_RxName(index) + local out = RxName[index] + return out or ("RX_" .. string.format("%X", index)) +end + +----------- Debugging 2-String functions ------------------------------------------------------------------- + +function MenuLib.phase2String(index) + local out = PhaseText[index] + return out or ("Phase_" .. string.format("%X", index)) +end + +function MenuLib.lineType2String(index) + local out = LineTypeText[index] + return out or ("LT_" .. string.format("%X", index or 0xFF)) +end + +function MenuLib.lineValue2String(l) + if (DEBUG_ON == 0) then + return "" + end + if (l ~= nil and l.Val ~= nil) then + local value = l.Val + if MenuLib.isListLine(l) then + value = value .. "|\"" .. MenuLib.Get_List_Text(l.Val + l.TextStart) .. "\"" + else + value = value..(l.Format or "") + end + return value + end + return "nil" +end + +function MenuLib.menu2String(m) + local txt = "Menu[]" + if (m ~= nil) then + txt = string.format("M[Id=0x%X P=0x%X N=0x%X B=0x%X Text=\"%s\"[0x%X]]", + m.MenuId, m.PrevId, m.NextId, m.BackId, m.Text, m.TextId) + end + return txt +end + +function MenuLib.menuLine2String(l) + local txt = "Line[]" + if (l ~= nil) then + local value = "" + local range = "" + if l.Type~=LINE_TYPE.MENU then + value = "Val="..MenuLib.lineValue2String(l) + if MenuLib.isListLine(l) then + range = string.format("NL=(%s->%s,%s,S=%s) ",l.Min, l.Max, l.Def, l.TextStart ) + range = range .. (l.MinMaxOrig or "") + else + range = string.format("[%s->%s,%s]",l.Min, l.Max, l.Def) + end + end + + txt = string.format("L[#%s T=%s VId=0x%X Text=\"%s\"[0x%X] %s %s MId=0x%X A=0x%X]", + l.lineNum, MenuLib.lineType2String(l.Type), l.ValId, + l.Text, l.TextId, + value, + range, + l.MenuId, + l.TextAttr + ) + end + return txt +end + +----------------------------------------------------------------------------------------------------------- +-- Post Procssing Line from Raw values receive by RX or Simulation + +function MenuLib.isDisplayAttr(attr, bit) + return (bit32.band(attr,bit)>0) +end + +function MenuLib.ExtractDisplayAttr(text1, attr) + local text = text1, pos; + + for i=1,2 do + text, pos = string.gsub(text, "/c$", "") + if (pos>0) then -- CENTER + attr = bit32.bor(attr, DISP_ATTR._CENTER) + end + + text, pos = string.gsub(text, "/r$", "") + if (pos>0) then -- RIGHT + attr = bit32.bor(attr, DISP_ATTR._RIGHT) + end + + text, pos = string.gsub(text, "/p$", "") + if (pos>0) then -- Percent TEXT + attr = bit32.bor(attr, DISP_ATTR.PERCENT) + end + + text, pos = string.gsub(text, "/b$", "") + if (pos>0) then -- BOLD TEXT + attr = bit32.bor(attr, DISP_ATTR._BOLD) + end + + text, pos = string.gsub(text, "/m$", "") + if (pos>0) then -- FORCED MENU Button + attr = bit32.bor(attr, DISP_ATTR.FORCED_MENU) + end + end + + return text, attr +end + +function MenuLib.MenuPostProcessing(menu) + menu.Text, menu.TextAttr = MenuLib.ExtractDisplayAttr(menu.Text,menu.TextAttr or 0) +end + +function MenuLib.MenuLinePostProcessing(line) + if (line.Text==nil) then + line.Text = MenuLib.Get_Text(line.TextId) -- Get Textual Line headeing text + end + + -- Text formatting options + line.Text, line.TextAttr = MenuLib.ExtractDisplayAttr(line.Text,line.TextAttr or 0) + + if line.Type == LINE_TYPE.MENU then + -- nothing to do on menu entries + line.Val=nil + elseif MenuLib.isListLine(line) then + -- Original Range for Debugging + line.MinMaxOrig = "[" .. line.Min .. "->" .. line.Max .. "," .. line.Def .. "]" + + -- Normalize Min/Max to be relative to Zero + line.TextStart = line.Min + line.Def = line.Def - line.Min -- normalize default value + line.Max = line.Max - line.Min -- normalize max index + line.Min = 0 -- min index + else -- default to numerical value + if MenuLib.isPercentValueLine(line) or MenuLib.isPercentValueLineByMinMax(line) then + -- either explicit Percent or NO-Change value, but range is %Percent + line.Format ="%" + line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.PERCENT) + elseif (line.Type == LINE_TYPE.VALUE_DEGREES) then + line.Format ="o" + line.TextAttr = bit32.bor(line.TextAttr,DISP_ATTR.DEGREES) + end + end + + line.MinMaxDebug = MenuLib.lineType2String(line.Type).." "..(line.MinMaxOrig or "") +end + + +function MenuLib.ChangePhase(newPhase) + DSM_Context.Phase = newPhase + DSM_Context.SendDataToRX = 1 +end + +function MenuLib.Value_Add(line, inc) + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Add(%s,%s)\n", + MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), inc, MenuLib.menuLine2String(line)) end + + local skipIncrement = false + local values = nil + local origVal = line.Val + + -- Use local validation for LIST_MENU1 when the range is wide open + -- Also use if for some LIST_MENU0 that the Range seems incorrect + if (MenuLib.isListLine(line)) then -- and line.Type==LINE_TYPE.LIST_MENU1 and line.Min==0 and line.Max==244) then + values = MenuLib.Get_List_Values(line.TextId) + end + + + if (values~=nil) then -- Inc/Dec based on a list of predefined Values Local to Script (values not contiguous), + -- locate current value in values array + -- Values are Zero normalized to the Start of the List (line.TextStart) + for i = 1, #values do + if ((values[i]-line.TextStart)==origVal) then + skipIncrement = true + if (inc==-1 and i > 1) then -- PREV + line.Val = values[i-1]-line.TextStart + elseif (inc==1 and i < #values) then -- NEXT + line.Val = values[i+1]-line.TextStart + end + break + end + end + end + + if not skipIncrement then + -- Do it Sequentially + line.Val = line.Val + inc + + if line.Val > line.Max then + line.Val = line.Max + elseif line.Val < line.Min then + line.Val = line.Min + end + end + + if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then + -- Update RX value on every change + MenuLib.ChangePhase(PHASE.VALUE_CHANGING) + end +end + +function MenuLib.Value_Default(line) + local origVal = line.Val + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Default(%s)\n", + MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end + + line.Val = line.Def + if (origVal~=line.Val and MenuLib.isIncrementalValueUpdate(line)) then + -- Update RX value on every change + MenuLib.ChangePhase(PHASE.VALUE_CHANGING) + end +end + +function MenuLib.Value_Write_Validate(line) + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_Value_Write_Validate(%s)\n", + MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), MenuLib.menuLine2String(line)) end + + MenuLib.ChangePhase(PHASE.VALUE_CHANGE_END) -- Update + Validate value in RX + DSM_Context.EditLine = nil -- Exit Edit Mode (By clearing the line editing) +end + +function MenuLib.GotoMenu(menuId, lastSelectedLine) + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: DSM_GotoMenu(0x%X,LastSelectedLine=%d)\n", + MenuLib.getElapsedTime(), MenuLib.phase2String(DSM_Context.Phase), menuId, lastSelectedLine) end + + DSM_Context.Menu.MenuId = menuId + DSM_Context.SelLine = lastSelectedLine + -- Request to load the menu Again + MenuLib.ChangePhase(PHASE.MENU_TITLE) +end + +function MenuLib.MoveSelectionLine(dir) + local ctx = DSM_Context + local menu = ctx.Menu + local menuLines = ctx.MenuLines + + if (dir == 1) then -- NEXT + if ctx.SelLine <= MAX_MENU_LINES then + local num = ctx.SelLine + for i = ctx.SelLine + 1, MAX_MENU_LINES, 1 do + if MenuLib.isSelectableLine(menuLines[i]) then + ctx.SelLine = i + break + end + end + + if num == ctx.SelLine then + if menu.NextId ~= 0 then -- Next + ctx.SelLine = NEXT_BUTTON + elseif menu.PrevId ~= 0 then -- Prev + ctx.SelLine = PREV_BUTTON + end + end + elseif menu.PrevId ~= 0 then -- Prev + ctx.SelLine = PREV_BUTTON + end + return + end + + if (dir == -1) then -- PREV + if ctx.SelLine == PREV_BUTTON and menu.NextId ~= 0 then + ctx.SelLine = NEXT_BUTTON + elseif ctx.SelLine > 0 then + if ctx.SelLine > MAX_MENU_LINES then + ctx.SelLine = NEXT_BUTTON + end + local num = ctx.SelLine + for i = ctx.SelLine - 1, 0, -1 do + if MenuLib.isSelectableLine(menuLines[i]) then + ctx.SelLine = i + break + end + end + if num == ctx.SelLine then -- can't find previous selectable line, then SELECT Back + if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end + end + else + if (menu.BackId ~= 0) then ctx.SelLine = BACK_BUTTON end -- Back + end + end +end + + +-- Clear each line of the menu +function MenuLib.clearMenuLines() + local ctx = DSM_Context + for i = 0, MAX_MENU_LINES do -- clear menu + ctx.MenuLines[i] = { MenuId = 0, lineNum = 0, Type = 0, Text = "", TextId = 0, ValId = 0, Min=0, Max=0, Def=0, TextStart=0, Val=nil } + end +end + +-- Post processing needed for each menu +function MenuLib.PostProcessMenu() + local ctx = DSM_Context + + if (ctx.Menu.Text==nil) then + ctx.Menu.Text = MenuLib.Get_Text(ctx.Menu.TextId) + MenuLib.MenuPostProcessing (ctx.Menu) + end + + --if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE Menu: %s\n", MenuLib.menu2String(ctx.Menu)) end + + for i = 0, MenuLib.MAX_MENU_LINES do -- clear menu + local line = ctx.MenuLines[i] + if (line.Type~=0) then + line.MenuId = ctx.Menu.MenuId + line.lineNum = i + MenuLib.MenuLinePostProcessing(line) -- Do the same post processing as if they come from the RX + --if (DEBUG_ON) then Log.LOG_write("SIM RESPONSE MenuLine: %s\n", MenuLib.menuLine2String(line)) end + end + + end +end + +function MenuLib.GetFlightModeValue(line) + local ret = line.Text.." " + local val = line.Val + + if (val==nil) then return ret.."--" end + + -- Adjust the displayed value for Flight mode line as needed + if (DSM_Context.RX.Id == RX.FC6250HX) then + -- Helicopter Flights modes + if (val==0) then ret = ret .. "1 / HOLD" + elseif (val==1) then ret = ret .. "2 / Normal" + elseif (val==2) then ret = ret .. "3 / Stunt 1" + elseif (val==3) then ret = ret .. "4 / Stunt 2" + elseif (val==4) then ret = ret .. "5 / Panic" + else + ret = ret .. " " .. (val + 1) + end + else + -- No adjustment needed + if (val==190) then + ret=ret.."Err:Out of Range" + else + ret=ret..(val + 1) + end + + end + return ret +end + +function MenuLib.Init() + print("MenuLib.Init()") + -- Phase Names + PhaseText[PHASE.INIT] = "INIT" + PhaseText[PHASE.RX_VERSION] = "RX_VERSION" + PhaseText[PHASE.WAIT_CMD] = "WAIT_CMD" + PhaseText[PHASE.MENU_TITLE] = "MENU_TITLE" + PhaseText[PHASE.MENU_REQ_TX_INFO] = "MENU_REQ_TX_INFO" + PhaseText[PHASE.MENU_LINES] = "MENU_LINES" + PhaseText[PHASE.MENU_VALUES] = "MENU_VALUES" + PhaseText[PHASE.VALUE_CHANGING] = "VALUE_CHANGING" + PhaseText[PHASE.VALUE_CHANGING_WAIT] = "VALUE_EDITING" + PhaseText[PHASE.VALUE_CHANGE_END] = "VALUE_CHANGE_END" + PhaseText[PHASE.EXIT] = "EXIT" + PhaseText[PHASE.EXIT_DONE] = "EXIT_DONE" + + + -- Line Types + LineTypeText[LINE_TYPE.MENU] = "M" + LineTypeText[LINE_TYPE.LIST_MENU_NC] = "LM_nc" + LineTypeText[LINE_TYPE.LIST_MENU] = "LM" + LineTypeText[LINE_TYPE.LIST_MENU_TOG] = "LM_tog" + LineTypeText[LINE_TYPE.LIST_MENU_NC2] = "LM_nc2" + LineTypeText[LINE_TYPE.LIST_MENU_ORI] = "LM_ori" + LineTypeText[LINE_TYPE.VALUE_NUM_I8_NC] = "V_nc" + LineTypeText[LINE_TYPE.VALUE_PERCENT] = "V_%" + LineTypeText[LINE_TYPE.VALUE_DEGREES] = "V_de" + LineTypeText[LINE_TYPE.VALUE_NUM_I8] = "V_i8" + LineTypeText[LINE_TYPE.VALUE_NUM_I16] = "V_i16" + LineTypeText[LINE_TYPE.VALUE_NUM_SI16] = "V_s16" + LineTypeText[LINE_TYPE.LT_EMPTY] = "Z" + + DSM_Context.Phase = PHASE.RX_VERSION +end + +function MenuLib.clearAllText() + local function clearTable(t) + for i, v in ipairs(t) do t[i] = nil end + end + + clearTable(Text) + clearTable(List_Text) + clearTable(List_Text_Img) + clearTable(List_Values) +end + +function MenuLib.LoadTextFromFile(fileName, mem) + local function rtrim(s) + local n = string.len(s) + while n > 0 and string.find(s, "^%s", n) do n = n - 1 end + return string.sub(s, 1, n) + end + + --print(string.format("Loading messages from [%s]",fileName)) + local dataFile = io.open(fileName, "r") -- read File + -- cannot read file??? + assert(dataFile, "Cannot load Message file:" .. fileName) + + local data = io.read(dataFile, mem * 1024) -- read up to 10k characters (newline char also counts!) + io.close(dataFile) + + collectgarbage("collect") + + local lineNo = 0 + for line in string.gmatch(data, "[^\r\n]+") do + lineNo = lineNo + 1 + --print(string.format("Line [%d]: %s",lineNo,line)) + + -- Remove Comments + local s = string.find(line, "--", 1, true) + if (s ~= nil) then + line = string.sub(line, 1, s - 1) + end + + line = rtrim(line) + + if (string.len(line) > 0) then + local a, b, c = string.match(line, "%s*(%a*)%s*|%s*(%w*)%s*|(.*)%s*") + --print(string.format("[%s] [%s] [%s]",a,b,c)) + if (a ~= nil) then + local index = tonumber(b) + + if (index == nil) then + assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, lineNo, b)) + elseif (a == "T") then + Text[index] = c + elseif (a == "LT") then + List_Text[index] = c + elseif (a == "LI") then + List_Text_Img[index] = c + elseif (a == "FM") then + Flight_Mode[0] = c + elseif (a == "RX") then + RxName[index] = c + else + assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, lineNo, a)) + end + end + end + if (lineNo % 50 == 0) then + collectgarbage("collect") + end + end -- For + + --print(string.format("Loaded [%d] messages",lineNo)) + data = nil +end + +function MenuLib.INC_LoadTextFromFile(fileName, FileState) + ----------------------- + local function rtrim(s) + local n = string.len(s) + while n > 0 and string.find(s, "^%s", n) do n = n - 1 end + return string.sub(s, 1, n) + end + + local function GetTextInfoFromFile(pos) + local dataFile = io.open(fileName, "r") + io.seek(dataFile,pos) + local buff = io.read(dataFile, 100) + io.close(dataFile) + + local line="" + local index="" + local type="" + + local pipe=0 + local comment=0 + local newPos = pos + + -- Parse the line: + -- Format: TT|0x999|Text -- Comment + for i=1,#buff do + newPos=newPos+1 + local ch = string.sub(buff,i,i) + + if (pipe < 2 and ch=="|") then pipe=pipe+1 -- Count pipes pos (Type | Index | .....) + elseif (ch=="\r") then -- Ignore CR + elseif (ch=="\n") then break -- LF, end of line + elseif (ch=="-") then -- March comments + comment=comment+1 + if (comment==2) then pipe=6 end -- Comment part of line + else + -- regular char + comment=0 + if (pipe==0) then type=type..ch -- in TT (Type) + elseif (pipe==1) then index=index..ch -- in Index + elseif (pipe<6) then line=line..ch end -- in Text + end -- Regular char + end -- For + + return type, index, rtrim(line), newPos + end + + ----------------------------------------------------------- + + if (FileState.state==nil) then -- Initial State + FileState.state=1 + FileState.lineNo=0 + FileState.filePos=0 + end + + if FileState.state==1 then + for l=1,10 do -- do 10 lines at a time + local type, sIndex, text + local lineStart = FileState.filePos + + type, sIndex, text, FileState.filePos = GetTextInfoFromFile(FileState.filePos) + + --print(string.format("T=%s, I=%s, T=%s LS=%d, FP=%d",type,sIndex,text,lineStart, FileState.filePos)) + + if (lineStart==FileState.filePos) then -- EOF + FileState.state=2 --EOF State + return 1 + end + FileState.lineNo = FileState.lineNo + 1 + + type = rtrim(type) + + if (string.len(type) > 0 and string.len(sIndex) > 0) then + local index = tonumber(sIndex) + + if (index == nil) then + assert(false, string.format("%s:%d: Invalid Hex num [%s]", fileName, FileState.lineNo, sIndex)) + elseif (type == "T") then + Text[index] = text + elseif (type == "LT") then + List_Text[index] = text + elseif (type == "LI") then + List_Text_Img[index] = text + elseif (type == "FM") then + Flight_Mode[0] = text + elseif (type == "RX") then + RxName[index] = text + else + assert(false, string.format("%s:%d: Invalid Line Type [%s]", fileName, FileState.lineNo, type)) + end + end + end -- for + end -- if + + return 0 + end + + +-- Export some Constants and Variables +MenuLib.PHASE = PHASE +MenuLib.LINE_TYPE = LINE_TYPE +MenuLib.DISP_ATTR = DISP_ATTR +MenuLib.RX = RX + +MenuLib.MAX_MENU_LINES = MAX_MENU_LINES +MenuLib.BACK_BUTTON = BACK_BUTTON +MenuLib.NEXT_BUTTON = NEXT_BUTTON +MenuLib.PREV_BUTTON = PREV_BUTTON + +MenuLib.DSM_Context = DSM_Context + +MenuLib.Text = Text +MenuLib.List_Text = List_Text +MenuLib.List_Text_Img = List_Text_Img +MenuLib.List_Values = List_Values + +MenuLib.LOG_open = Log.LOG_open +MenuLib.LOG_write = Log.LOG_write +MenuLib.LOG_Close = Log.LOG_close + + +return MenuLib \ No newline at end of file diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmModelLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmModelLib.lua new file mode 100644 index 0000000..357c4a5 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmModelLib.lua @@ -0,0 +1,789 @@ + +local Log, DEBUG_ON = ... + +local DATA_PATH = "/MODELS/DSMDATA" -- Path to store model settings files +local TX_CHANNELS = 12 + +-- MODEL information from ETX/OTX +local ModelLib = {} + +local MODEL = { + modelName = "", -- The name of the model comming from OTX/ETX + modelOutputChannel = {}, -- Output information from OTX/ETX + AirWingTailDesc = "", + + TX_CH_TEXT = {}, + PORT_TEXT = {}, + DSM_ChannelInfo = {} -- Data Created by DSM Configuration Script +} + +--Channel Types -- +local CH_TYPE = { + NONE = 0x00, + AIL = 0x01, + ELE = 0x02, + RUD = 0x04, + + REVERSE = 0x20, + THR = 0x40, + SLAVE = 0x80, +} + +-- Seems like Reverse Mix is complement of the 3 bits +local CH_MIX_TYPE = { + MIX_NORM = 0x00, -- 0000 + MIX_AIL = 0x10, -- 0001 Taileron + MIX_ELE = 0x20, -- 0010 For VTIAL and Delta-ELEVON + MIX_RUD = 0x30, -- 0011 For VTIAL + + MIX_RUD_REV = 0x40, -- 0100 For VTIAL + MIX_ELE_REV = 0x50, -- 0101 For VTIAL and Delta-ELEVON A + MIX_AIL_REV = 0x60, -- 0110 Taileron + MIX_NORM_REV = 0x70 -- 0111 +} + +local AIRCRAFT_TYPE = { + PLANE = 0, + HELI = 1, + GLIDER = 2, + DRONE = 3 +} +local aircraft_type_text = {[0]="Plane","Heli","Glider","Drone"} + +local WING_TYPE = { + AIL_1 = 0, --1 + AIL_2 = 1, --2 + FLAPERON = 2, --2 + AIL_1_FLP_1 = 3, --2 + AIL_2_FLP_1 = 4, --3 + AIL_2_FLP_2 = 5, --4 + ELEVON_A = 6, --2 + ELEVON_B = 7 --2 +} + +local wing_type_text = {[0]="Normal","Dual Ail","Flapperon", "Ail + Flp","Dual Ail + Flp","Dual Ail/Flp","Elevon A","Elevon B"} + +local TAIL_TYPE = { + RUD_1 = 0, -- 1 + RUD_1_ELEV_1 = 1, -- 2 + RUD_1_ELEV_2 = 2, -- 3 + RUD_2_ELEV_1 = 3, -- 3 + RUD_2_ELEV_2 = 4, -- 4 + VTAIL_A = 5, -- 2 + VTAIL_B = 6, -- 2 + TRAILERON_A = 7, -- 3 + TRAILERON_B = 8, -- 3 + TRAILERON_A_R2 = 9, -- 3 + TRAILERON_B_R2 = 10 -- 3 +} +local tail_type_text = {[0]="Rud Only","Normal","Rud + Dual Ele","Dual Rud + Elv","Dual Rud/Ele", + "VTail A","VTail B","Taileron A","Taileron B","Taileron A + 2x Rud","Taileron B + 2x Rud"} + +local CH_MODE_TYPE = { + NORMAL = 0, + REVERSE = 1, + USE_TX = 3 +} + +local PORT = { + PORT1 = 0, + PORT2 = 1, + PORT3 = 2, + PORT4 = 3, + PORT5 = 4, + PORT6 = 5, + PORT7 = 6, + PORT8 = 7, + PORT9 = 8, + PORT10 = 9, + PORT11 = 10, + PORT12 = 11 +} + +local MEMU_VAR = { + AIRCRAFT_TYPE = 1001, + WING_TYPE = 1002, + TAIL_TYPE = 1003, + + CH_BASE = 1010, + CH_THR = 1010, + + CH_L_AIL = 1011, + CH_R_AIL = 1012, + CH_L_FLP = 1013, + CH_R_FLP = 1014, + + CH_L_RUD = 1015, + CH_R_RUD = 1016, + CH_L_ELE = 1017, + CH_R_ELE = 1018, + + PORT_BASE = 1020, + PORT1_MODE = 1020, + PORT2_MODE = 1021, + PORT3_MODE = 1022, + PORT4_MODE = 1023, + PORT5_MODE = 1024, + PORT6_MODE = 1025, + PORT7_MODE = 1026, + PORT8_MODE = 1027, + PORT9_MODE = 1028, + PORT10_MODE = 1029, + PORT11_MODE = 1030, + PORT12_MODE = 1031, + + DATA_END = 1040 +} + + +-- MENU DATA Management +local MENU_DATA = {} -- Store the variables used in the Menus. + + +---- DSM_ChannelInfo --------------------------------- +-- First byte describe Special Mixing (Vtail/Elevon = 0x20) +--VTAIL +--(0x00 0x06) CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06) +--(0x20 0x86) CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86) + +-- The 2nd byte describes the functionality of the port +-- +-- Single Example: CH_TYPE.AIL (0x01) Aileron +-- Reverse Example: CH_TYPE.AIL+CH_TYPE.REVERSE (0x01+0x20=0x21) Reverse Aileron +-- Slave Example: CH_TYPE.AIL+CH_TYPE.SLAVE (0x01+0x80) -- 2nd servo Aileron + +-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE (0x01+0x02 = 0x03) -- Elevon +-- Elevon Example: CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE (0x01+0x02+0x80 = 0x83) -- Slave Elevon + +-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD (0x02+0x04 = 0x06) -- Rudevator +-- RudElv (VTail) Example: CH_TYPE.ELE+CH_TYPE.RUD+CH_TYPE.SLAVE (0x02+0x04+0x80 = 0x86) -- Rudevator Slave + +-- DEFAULT Simple Plane Port configuration (The Configuration tool will overrride this) +MODEL.DSM_ChannelInfo= {[0]= -- Start array at position 0 + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.THR}, -- Ch1 Thr (0x40) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.AIL}, -- Ch2 Ail (0x01) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.ELE}, -- Ch2 ElE (0x02) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.RUD}, -- Ch4 Rud (0x04) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch5 Gear (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch6 Aux1 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch7 Aux2 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch8 Aux3 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch9 Aux4 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch10 Aux5 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE}, -- Ch11 Aux6 (0x00) + {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Ch12 Aux7 (0x00) + } + +function ModelLib.printChannelSummary(a,w,t) + -- Summary + print("CHANNEL INFORMATION") + print("Aircraft:".. (aircraft_type_text[MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]] or "--")) + print("Wing Type:".. (wing_type_text[MENU_DATA[MEMU_VAR.WING_TYPE]] or "--")) + print("Tail Type:".. (tail_type_text[MENU_DATA[MEMU_VAR.TAIL_TYPE]] or "--")) + print("Thr:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_THR] or 30)] or "--")) -- use fake ch30 for non existing channels + print("LAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_AIL] or 30)] or "--")) + print("RAil:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_AIL] or 30)] or "--")) + print("LFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_FLP] or 30)] or "--")) + print("RFlp:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_FLP] or 30)] or "--")) + print("LEle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_ELE] or 30)] or "--")) + print("REle:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_ELE] or 30)] or "--")) + print("LRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_L_RUD] or 30)] or "--")) + print("RRud:".. (MODEL.PORT_TEXT[(MENU_DATA[MEMU_VAR.CH_R_RUD] or 30)] or "--")) +end + +function ModelLib.printServoReverseInfo() + print("SERVO Normal/Reverse INFORMATION") + for i=0, TX_CHANNELS-1 do + local s="--" + if (MENU_DATA[MEMU_VAR.PORT1_MODE+i] or 0) == 0 then s="NORMAL" else s="REVERSE" end + print(string.format("Port%d: %s", i+1, s)) + end +end + +function ModelLib.channelType2String(byte1, byte2) + local s = "" + + if (byte2==0) then return s end; + + if (bit32.band(byte2,CH_TYPE.AIL)>0) then s=s.."Ail" end + if (bit32.band(byte2,CH_TYPE.ELE)>0) then s=s.."Ele" end + if (bit32.band(byte2,CH_TYPE.RUD)>0) then s=s.."Rud" end + if (bit32.band(byte2,CH_TYPE.THR)>0) then s=s.."Thr" end + + if (bit32.band(byte2,CH_TYPE.REVERSE)>0) then s=s.."-" end + + if (bit32.band(byte2,CH_TYPE.SLAVE)>0) then s=s.." Slv" end + + if (byte1==CH_MIX_TYPE.MIX_NORM) then s=s.." " + elseif (byte1==CH_MIX_TYPE.MIX_AIL) then s=s.." M_Ail" + elseif (byte1==CH_MIX_TYPE.MIX_ELE) then s=s.." M_Ele" + elseif (byte1==CH_MIX_TYPE.MIX_RUD) then s=s.." M_Rud" + elseif (byte1==CH_MIX_TYPE.MIX_RUD_REV) then s=s.." M_Rud-" + elseif (byte1==CH_MIX_TYPE.MIX_ELE_REV) then s=s.." M_Ele-" + elseif (byte1==CH_MIX_TYPE.MIX_AIL_REV) then s=s.." M_Ail-" + elseif (byte1==CH_MIX_TYPE.MIX_NORM_REV) then s=s.." M-" + end + + return s; +end + + +------------------------------------------------------------------------------------------------- +-- Read the model information from OTX/ETX + +local function getModuleChannelOrder(num) + --Determine fist 4 channels order + local channel_names={} + local stick_names = {[0]= "R", "E", "T", "A" } + local ch_order=num + if (ch_order == -1) then + channel_names[0] = stick_names[3] + channel_names[1] = stick_names[1] + channel_names[2] = stick_names[2] + channel_names[3] = stick_names[0] + else + channel_names[bit32.band(ch_order,3)] = stick_names[3] + ch_order = math.floor(ch_order/4) + channel_names[bit32.band(ch_order,3)] = stick_names[1] + ch_order = math.floor(ch_order/4) + channel_names[bit32.band(ch_order,3)] = stick_names[2] + ch_order = math.floor(ch_order/4) + channel_names[bit32.band(ch_order,3)] = stick_names[0] + end + + local s = "" + for i=0,3 do + s=s..channel_names[i] + end + return s +end + +function ModelLib.ReadTxModelData() + local TRANSLATE_AETR_TO_TAER=false + local table = model.getInfo() -- Get the model name + MODEL.modelName = table.name + + local module = model.getModule(0) -- Internal + if (module==nil or module.Type~=6) then module = model.getModule(1) end -- External + if (module~=nil) then + if (module.Type==6 ) then -- MULTI-MODULE + local chOrder = module.channelsOrder + local s = getModuleChannelOrder(chOrder) + Log.LOG_write("MultiChannel Ch Order: [%s] %s\n",chOrder,s) + + if (s=="AETR") then TRANSLATE_AETR_TO_TAER=true + else TRANSLATE_AETR_TO_TAER=false + end + end + end + + Log.LOG_write("MODEL NAME = %s\n",MODEL.modelName) + + -- Read Ch1 to Ch10 + local i= 0 + for i = 0, TX_CHANNELS-1 do + local ch = model.getOutput(i) -- Zero base + if (ch~=nil) then + MODEL.modelOutputChannel[i] = ch + if (string.len(ch.name)==0) then + ch.formatCh = string.format("TX:Ch%i",i+1) + else + ch.formatCh = string.format("TX:Ch%i/%s",i+1,ch.name or "--") + end + end + end + + -- Translate AETR to TAER + -- TODO: Check if there is a way to know how to the TX is configured, since if it is + -- already TAER, is not needed + + if (TRANSLATE_AETR_TO_TAER) then + Log.LOG_write("Applying AETR -> TAER translation\n") + local ail = MODEL.modelOutputChannel[0] + local elv = MODEL.modelOutputChannel[1] + local thr = MODEL.modelOutputChannel[2] + + MODEL.modelOutputChannel[0] = thr + MODEL.modelOutputChannel[1] = ail + MODEL.modelOutputChannel[2] = elv + end + + -- Create the Port Text to be used + Log.LOG_write("Ports/Channels:\n") + for i = 0, TX_CHANNELS-1 do + local ch = MODEL.modelOutputChannel[i] + if (ch~=nil) then + MODEL.TX_CH_TEXT[i] = ch.formatCh + MODEL.PORT_TEXT[i] = string.format("P%i (%s) ",i+1,MODEL.TX_CH_TEXT[i]) + + Log.LOG_write("Port%d %s [%d,%d] Rev=%d, Off=%d, ppmC=%d, syn=%d\n",i+1,MODEL.TX_CH_TEXT[i],math.floor(ch.min/10),math.floor(ch.max/10), ch.revert, ch.offset, ch.ppmCenter, ch.symetrical) + end + end +end + +----------------------- FILE MANAGEMENT --------------------------------------------- +-- Create a fairly unique name for a model..combination of name and a hash +-- TODO: Check with ETX why we can't get the filename used to store the model info +-- Improvement request?? + +function ModelLib.hashName(mName) + local c=10000; + + local prefix = string.gsub(mName,"%.","_") -- Change any "." to "_" + prefix = string.gsub(prefix,"% ","_") -- Change any space to "_" + prefix = string.sub(prefix,1,5) -- Take the first 5 characters + + -- Simple Hash of the Model Name adding each character + for i = 1, #mName do + local ch = string.byte(mName,i,i) + c=c+ch + end + + return (prefix .. c) -- Return Prefix + Hash +end + +-- Load Menu Data from a file +function ModelLib.ST_LoadFileData() + local fname = ModelLib.hashName(MODEL.modelName)..".txt" + + -- Clear Menu Data + for i = 0, MEMU_VAR.DATA_END do + MENU_DATA[i]=nil + end + + print("Loading File:"..fname) + + local dataFile = io.open(DATA_PATH .. "/".. fname, "r") -- read File + -- cannot read file??? + if (dataFile==nil) then return 0 end + + local line = io.read(dataFile, 5000) + io.close(dataFile) + + if #line == 0 then return 0 end -- No data?? + + -- Process the input, each line is "Var_Id : Value" format + -- Store it into MANU_DATA + local i=0 + for k, v in string.gmatch(line, "(%d+):(%d+)") do + --print(string.format("Read MENU_DATA[%d]:[%d]",k, v)) + MENU_DATA[k+0]=v+0 -- do aritmentic to convert string to number + i=i+1 + end + + local currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] + local currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + local currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE] + + print("Validation") + print(string.format("AIRCRAFT_TYPE(%d)=%s", MEMU_VAR.AIRCRAFT_TYPE,aircraft_type_text[currAircraftType])) + print(string.format("WING_TYPE(%d)=%s", MEMU_VAR.WING_TYPE, wing_type_text[currWingType])) + print(string.format("TAIL_TYPE(%d)=%s", MEMU_VAR.TAIL_TYPE, tail_type_text[currTailType])) + + ModelLib.printChannelSummary() + ModelLib.printServoReverseInfo() + + -- Return 0 if no lines processed, 1 otherwise + if (i > 0) then return 1 else return 0 end +end + +-- Saves MENU_DATA to a file +function ModelLib.ST_SaveFileData() + local fname = ModelLib.hashName(MODEL.modelName)..".txt" + + print("Saving File:"..fname) + local dataFile = assert(io.open(DATA_PATH .. "/" .. fname, "w"),"Please create "..DATA_PATH.." folder") -- write File + + -- Foreach MENU_DATA with a value write Var_Id:Value into file + for i = 0, MEMU_VAR.DATA_END do + if (MENU_DATA[i]~=nil) then + --print(string.format("Write MENU_DATA[%s] : %s",i,MENU_DATA[i])) + io.write(dataFile,string.format("%s:%s\n",i,MENU_DATA[i])) + end + end + io.close(dataFile) +end + +-- This Creates the Servo Settings that will be used to pass to +-- Forward programming +function ModelLib.CreateDSMPortChannelInfo() + local function ApplyWingMixA(b2) + -- ELEVON + if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x03 + if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83 + end + + local function ApplyWingMixB(b2) + -- ELEVON + if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03 + if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x83 + end + + local function ApplyTailMixA(b2) + -- VTAIL + -- Default normal/reverse behaviour + if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06 + if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_ELE end; -- 0x86 + + --TAILERON + -- Default normal/reverse behaviour + if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x03 + if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x83 + end + + local function ApplyTailMixB(b2) + -- VTAIL + -- Default normal/reverse behaviour + if (b2==CH_TYPE.RUD+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x06 + if (b2==CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_RUD end; -- 0x86 + + --TAILERON + if (b2==CH_TYPE.AIL+CH_TYPE.ELE) then return CH_MIX_TYPE.MIX_AIL end; -- 0x03 + if (b2==CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE) then return CH_MIX_TYPE.MIX_NORM end; -- 0x83 + end + + local function reverseMix(b) + if (b==CH_MIX_TYPE.MIX_NORM) then return CH_MIX_TYPE.MIX_NORM_REV end; + if (b==CH_MIX_TYPE.MIX_AIL) then return CH_MIX_TYPE.MIX_AIL_REV end; + if (b==CH_MIX_TYPE.MIX_ELE) then return CH_MIX_TYPE.MIX_ELE_REV end; + if (b==CH_MIX_TYPE.MIX_RUD) then return CH_MIX_TYPE.MIX_RUD_REV end; + return b + end + + + + local DSM_ChannelInfo = MODEL.DSM_ChannelInfo + + for i=0, TX_CHANNELS-1 do + DSM_ChannelInfo[i] = {[0]= CH_MIX_TYPE.MIX_NORM, CH_TYPE.NONE} -- Initialize with no special function + end + + local aircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] + local wingType = MENU_DATA[MEMU_VAR.WING_TYPE] + local tailType = MENU_DATA[MEMU_VAR.TAIL_TYPE] + + local thrCh = MENU_DATA[MEMU_VAR.CH_THR] + local lAilCh = MENU_DATA[MEMU_VAR.CH_L_AIL] + local rAilCh = MENU_DATA[MEMU_VAR.CH_R_AIL] + local lflapCh = MENU_DATA[MEMU_VAR.CH_L_FLP] + local rflapCh = MENU_DATA[MEMU_VAR.CH_R_FLP] + + local lElevCh = MENU_DATA[MEMU_VAR.CH_L_ELE] + local rElevCh = MENU_DATA[MEMU_VAR.CH_R_ELE] + + local lRudCh = MENU_DATA[MEMU_VAR.CH_L_RUD] + local rRudCh = MENU_DATA[MEMU_VAR.CH_R_RUD] + + -- Channels in menu vars are Zero base, Channel info is 1 based + + -- THR + if (thrCh~=nil and thrCh < 10) then DSM_ChannelInfo[thrCh][1]= CH_TYPE.THR end + + -- AIL (Left and Right) + if (lAilCh~=nil) then DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL end + if (rAilCh~=nil) then DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.SLAVE end + -- ELE (Left and Right) + if (lElevCh~=nil) then DSM_ChannelInfo[lElevCh][1] = CH_TYPE.ELE end + if (rElevCh~=nil) then DSM_ChannelInfo[rElevCh][1] = CH_TYPE.ELE+CH_TYPE.SLAVE end + -- RUD (Left and Right) + if (lRudCh~=nil) then DSM_ChannelInfo[lRudCh][1] = CH_TYPE.RUD end + if (rRudCh~=nil) then DSM_ChannelInfo[rRudCh][1] = CH_TYPE.RUD+CH_TYPE.SLAVE end + + -- VTAIL: RUD + ELE + if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.VTAIL_B) then + DSM_ChannelInfo[lElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE + DSM_ChannelInfo[rElevCh][1] = CH_TYPE.RUD+CH_TYPE.ELE+CH_TYPE.SLAVE + end + + -- TAILERRON: 2-ELE + AIL + if (tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or + tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then + DSM_ChannelInfo[lElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE + DSM_ChannelInfo[rElevCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE + end + + ---- ELEVON : AIL + ELE + if (wingType==WING_TYPE.ELEVON_A or wingType==WING_TYPE.ELEVON_B) then + DSM_ChannelInfo[lAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE + DSM_ChannelInfo[rAilCh][1] = CH_TYPE.AIL+CH_TYPE.ELE+CH_TYPE.SLAVE + end + + ------MIXES --------- + + -- TAIL Mixes (Elevator and VTail) + if (tailType==TAIL_TYPE.VTAIL_A or tailType==TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2) then + DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1]) + DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1]) + elseif (tailType==TAIL_TYPE.VTAIL_B or tailType==TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then + DSM_ChannelInfo[lElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[lElevCh][1]) + DSM_ChannelInfo[rElevCh][0] = ApplyTailMixA(DSM_ChannelInfo[rElevCh][1]) + end + + ---- Wing Mixes + if (wingType==WING_TYPE.ELEVON_A) then + DSM_ChannelInfo[lAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[lAilCh][1]) + DSM_ChannelInfo[rAilCh][0] = ApplyWingMixA(DSM_ChannelInfo[rAilCh][1]) + elseif (wingType==WING_TYPE.ELEVON_B) then + DSM_ChannelInfo[lAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[lAilCh][1]) + DSM_ChannelInfo[rAilCh][0] = ApplyWingMixB(DSM_ChannelInfo[rAilCh][1]) + end + + -- Apply Gyro Reverse as needed for each channel as long as it is used + for i=0, TX_CHANNELS-1 do + if (MENU_DATA[MEMU_VAR.PORT_BASE+i]==CH_MODE_TYPE.REVERSE and DSM_ChannelInfo[i][1]>0) then + DSM_ChannelInfo[i][0]=reverseMix(DSM_ChannelInfo[i][0]) + DSM_ChannelInfo[i][1]=DSM_ChannelInfo[i][1]+CH_TYPE.REVERSE + end + end + + -- Show how it looks + for i=0, 9 do + local b1,b2 = DSM_ChannelInfo[i][0], DSM_ChannelInfo[i][1] + print(string.format("%s (%02X %02X) %s", MODEL.PORT_TEXT[i], + b1, b2, ModelLib.channelType2String(b1,b2))) + end + + MODEL.AirWingTailDesc = string.format("Aircraft(%s) Wing(%s) Tail(%s)",aircraft_type_text[aircraftType],wing_type_text[wingType],tail_type_text[tailType]) +end + +function ModelLib.ST_PlaneWingInit(wingType) + print("Change Plane WingType:"..wing_type_text[wingType]) + + MENU_DATA[MEMU_VAR.WING_TYPE] = wingType + + -- Clear all Wing Data + MENU_DATA[MEMU_VAR.CH_L_AIL] = nil + MENU_DATA[MEMU_VAR.CH_R_AIL] = nil + MENU_DATA[MEMU_VAR.CH_L_FLP] = nil + MENU_DATA[MEMU_VAR.CH_R_FLP] = nil + + MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT1 + + -- Default Channel Assisgments for each Wing type + + if (wingType==WING_TYPE.AIL_1) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2 + elseif (wingType==WING_TYPE.AIL_2) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + elseif (wingType==WING_TYPE.FLAPERON) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + elseif (wingType==WING_TYPE.AIL_1_FLP_1) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT6 + elseif (wingType==WING_TYPE.AIL_2_FLP_1) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5 + elseif (wingType==WING_TYPE.AIL_2_FLP_2) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT6 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT5 + MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT7 + elseif (wingType==WING_TYPE.ELEVON_A) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT3 + elseif (wingType==WING_TYPE.ELEVON_B) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + else -- Assume normal + print("ERROR: Invalid Wing Type") + end + + + ModelLib.printChannelSummary() +end + +function ModelLib.ST_PlaneTailInit(tailType) + if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A or + MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_B) then + tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder + end + + print("Change Plane Tail Type:"..tail_type_text[tailType]) + + -- Clear all data for Tail + MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType + MENU_DATA[MEMU_VAR.CH_L_ELE] = nil + MENU_DATA[MEMU_VAR.CH_R_ELE] = nil + MENU_DATA[MEMU_VAR.CH_L_RUD] = nil + MENU_DATA[MEMU_VAR.CH_R_RUD] = nil + + -- Setup Channels for different Tail types + if (tailType == TAIL_TYPE.RUD_1) then + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + elseif (tailType == TAIL_TYPE.RUD_1_ELEV_2) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + elseif (tailType == TAIL_TYPE.RUD_2_ELEV_1) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT5 + elseif (tailType == TAIL_TYPE.RUD_2_ELEV_2) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT6 + elseif (tailType == TAIL_TYPE.VTAIL_A or tailType == TAIL_TYPE.VTAIL_B) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3 + elseif (tailType == TAIL_TYPE.TRAILERON_A or tailType==TAIL_TYPE.TRAILERON_A_R2 or + tailType == TAIL_TYPE.TRAILERON_B or tailType==TAIL_TYPE.TRAILERON_B_R2) then + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT5 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3 + else -- Assume Normal + print("ERROR:invalid Tail Type") + end + + if (tailType == TAIL_TYPE.TRAILERON_A_R2 or tailType==TAIL_TYPE.TRAILERON_B_R2) then + MENU_DATA[MEMU_VAR.CH_R_RUD] = PORT.PORT7 + end + + ModelLib.printChannelSummary() +end + +function ModelLib.ST_GliderWingInit(wingType) + print("Change Glider WingType:"..wing_type_text[wingType]) + + MENU_DATA[MEMU_VAR.WING_TYPE] = wingType + + -- Clear all Wing Data + MENU_DATA[MEMU_VAR.CH_L_AIL] = nil + MENU_DATA[MEMU_VAR.CH_R_AIL] = nil + MENU_DATA[MEMU_VAR.CH_L_FLP] = nil + MENU_DATA[MEMU_VAR.CH_R_FLP] = nil + MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT6 + + -- Default Channel Assisgments for each Wing type + + if (wingType==WING_TYPE.AIL_1) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1 + elseif (wingType==WING_TYPE.AIL_2) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + elseif (wingType==WING_TYPE.AIL_2_FLP_1) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5 + elseif (wingType==WING_TYPE.AIL_2_FLP_2) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_L_FLP] = PORT.PORT5 + MENU_DATA[MEMU_VAR.CH_R_FLP] = PORT.PORT6 + MENU_DATA[MEMU_VAR.CH_THR] = PORT.PORT7 + elseif (wingType==WING_TYPE.ELEVON_A) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT1 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT2 + elseif (wingType==WING_TYPE.ELEVON_B) then + MENU_DATA[MEMU_VAR.CH_L_AIL] = PORT.PORT2 + MENU_DATA[MEMU_VAR.CH_R_AIL] = PORT.PORT1 + else -- Assume normal + print("ERROR: Invalid Wing Type") + end + + ModelLib.printChannelSummary() +end + +function ModelLib.ST_GliderTailInit(tailType) + if (MENU_DATA[MEMU_VAR.WING_TYPE]==WING_TYPE.ELEVON_A) then + tailType = TAIL_TYPE.RUD_1 -- Delta only have ruder + end + + print("Change Glider Tail Type:"..tail_type_text[tailType]) + + -- Clear all data for Tail + MENU_DATA[MEMU_VAR.TAIL_TYPE] = tailType + MENU_DATA[MEMU_VAR.CH_L_ELE] = nil + MENU_DATA[MEMU_VAR.CH_R_ELE] = nil + MENU_DATA[MEMU_VAR.CH_L_RUD] = nil + MENU_DATA[MEMU_VAR.CH_R_RUD] = nil + + -- Setup Channels for different Tail types + if (tailType == TAIL_TYPE.RUD_1) then + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + elseif (tailType == TAIL_TYPE.RUD_1_ELEV_1) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_L_RUD] = PORT.PORT4 + elseif (tailType == TAIL_TYPE.VTAIL_A) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT4 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT3 + elseif (tailType == TAIL_TYPE.VTAIL_B) then + MENU_DATA[MEMU_VAR.CH_L_ELE] = PORT.PORT3 + MENU_DATA[MEMU_VAR.CH_R_ELE] = PORT.PORT4 + else -- Assume Normal + print("ERROR: Invalid Tail Type") + end + + ModelLib.printChannelSummary() +end + + +function ModelLib.ST_AircraftInit(aircraftType) + MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] = aircraftType + + print("Change Aircraft:".. aircraft_type_text[aircraftType]) + + -- Setup Default Aircraft Wing/Tail + if (aircraftType==AIRCRAFT_TYPE.PLANE) then + ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1) + ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1) + elseif (aircraftType==AIRCRAFT_TYPE.GLIDER) then + ModelLib.ST_GliderWingInit(WING_TYPE.AIL_1) + ModelLib.ST_GliderTailInit(TAIL_TYPE.RUD_1_ELEV_1) + else + ModelLib.ST_PlaneWingInit(WING_TYPE.AIL_1) + ModelLib.ST_PlaneTailInit(TAIL_TYPE.RUD_1_ELEV_1) + end + + +end + + +-- Setup Initial Default Data for the Menus +function ModelLib.ST_Default_Data() + print("Initializing Menu DATA") + ModelLib.ST_AircraftInit(AIRCRAFT_TYPE.PLANE) + + print("Initializing Servo Reverse from TX output settings") + + MENU_DATA[MEMU_VAR.PORT1_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT1].revert + MENU_DATA[MEMU_VAR.PORT2_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT2].revert + MENU_DATA[MEMU_VAR.PORT3_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT3].revert + MENU_DATA[MEMU_VAR.PORT4_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT4].revert + MENU_DATA[MEMU_VAR.PORT5_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT5].revert + MENU_DATA[MEMU_VAR.PORT6_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT6].revert + MENU_DATA[MEMU_VAR.PORT7_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT7].revert + MENU_DATA[MEMU_VAR.PORT8_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT8].revert + MENU_DATA[MEMU_VAR.PORT9_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT9].revert + MENU_DATA[MEMU_VAR.PORT10_MODE] = CH_MODE_TYPE.NORMAL + MODEL.modelOutputChannel[PORT.PORT10].revert + + ModelLib.printServoReverseInfo() + +end + + +ModelLib.TX_CHANNELS = TX_CHANNELS +ModelLib.MODEL = MODEL +ModelLib.CH_TYPE = CH_TYPE +ModelLib.CH_MODE_TYPE = CH_MODE_TYPE +ModelLib.AIRCRAFT_TYPE = AIRCRAFT_TYPE +ModelLib.WING_TYPE = WING_TYPE +ModelLib.TAIL_TYPE = TAIL_TYPE +ModelLib.MENU_DATA = MENU_DATA +ModelLib.MEMU_VAR = MEMU_VAR +ModelLib.PORT = PORT +ModelLib.DATA_PATH = DATA_PATH + +ModelLib.aircraft_type_text = aircraft_type_text +ModelLib.wing_type_text = wing_type_text +ModelLib.tail_type_text = tail_type_text + + +return ModelLib + diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmSetupMenuLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmSetupMenuLib.lua new file mode 100644 index 0000000..7c998fa --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmSetupMenuLib.lua @@ -0,0 +1,467 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- This scrip does the airplane Setup similar to how a a Spektrum radio does +-- it. You can select the plane type, the Wing type, etc. +-- This settings are needed for ForwardProgramming to send the TX aircraft +-- configuration to the RX when in Initial Setup +-- Author: Francisco Arzu +------------------------------------------------------------------------------ + +local Log, menuLib, modelLib, DEBUG_ON, SIMULATION_ON = ... -- Get DebugON from parameters +local SETUP_LIB_VERSION = "0.56" + +local DATA_PATH = modelLib.DATA_PATH + +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE + +local MODEL = modelLib.MODEL + +local AIRCRAFT_TYPE = modelLib.AIRCRAFT_TYPE +local WING_TYPE = modelLib.WING_TYPE +local TAIL_TYPE = modelLib.TAIL_TYPE +local CH_MODE_TYPE = modelLib.CH_MODE_TYPE +local PORT = modelLib.PORT +local MEMU_VAR = modelLib.MEMU_VAR +local MENU_DATA = modelLib.MENU_DATA + +local SetupLib = {} + +local lastGoodMenu=0 + +------------------- Model Setup Helper functions ---------------------- +local currAircraftType = -1 -- Current AircraftType selected, and to detect change +local currTailType = -1 -- Current WingType selected, and to detect change +local currWingType = -1 -- Current TailType selected, and to detect change + +local menuDataChanged = false -- Flag to notify if any data has changed + + +local function tailTypeCompatible(a,b) + + local function normalize(tt) + if (tt==TAIL_TYPE.TRAILERON_A or tt==TAIL_TYPE.TRAILERON_B) then + return TAIL_TYPE.TRAILERON_A + elseif (tt==TAIL_TYPE.TRAILERON_A_R2 or tt==TAIL_TYPE.TRAILERON_B_R2) then + return TAIL_TYPE.TRAILERON_A_R2 + elseif (tt==TAIL_TYPE.VTAIL_A or tt==TAIL_TYPE.VTAIL_B) then + return TAIL_TYPE.VTAIL_A + else + return tt + end + end + + return (normalize(a)==normalize(b)) + end + + +-- Creates the menus to Render with the GUI +local function ST_LoadMenu(menuId) + local ctx = menuLib.DSM_Context + + local function portUse(p) + local out = "" + if p==MENU_DATA[MEMU_VAR.CH_THR] then out = "Thr" + elseif p == MENU_DATA[MEMU_VAR.CH_L_AIL] then + out=(MENU_DATA[MEMU_VAR.CH_R_AIL] and "Ail_L") or "Ail" + elseif p == MENU_DATA[MEMU_VAR.CH_R_AIL] then out="Ail_R" + elseif p == MENU_DATA[MEMU_VAR.CH_L_ELE] then + out=(MENU_DATA[MEMU_VAR.CH_R_ELE] and "Ele_L") or "Ele" + elseif p == MENU_DATA[MEMU_VAR.CH_R_ELE] then out="Ele_R" + elseif p == MENU_DATA[MEMU_VAR.CH_L_RUD] then + out=(MENU_DATA[MEMU_VAR.CH_R_RUD] and "Rud_L") or "Rud" + elseif p == MENU_DATA[MEMU_VAR.CH_R_RUD] then out="Rud_R" + elseif p == MENU_DATA[MEMU_VAR.CH_L_FLP] then + out=(MENU_DATA[MEMU_VAR.CH_R_FLP] and "Flp_L") or "Flp" + elseif p == MENU_DATA[MEMU_VAR.CH_R_FLP] then out="Flp_R" + end + return out + end + + local function formatTXRevert(port) + local out = " " .. modelLib.channelType2String(MODEL.DSM_ChannelInfo[port][0], MODEL.DSM_ChannelInfo[port][1]); + return out + end + + local function Header(p) + return MODEL.PORT_TEXT[p].." "..portUse(p) + end + + menuLib.clearMenuLines() + + + if (menuId==0x1000) then -- MAIN MENU + ctx.Menu = { MenuId = 0x1000, Text = "Save-Exit ("..MODEL.modelName..")", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + + if (true) then + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, Text="Save Changes", TextId = 0, ValId = 0x1005 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Discard Changes", TextId = 0, ValId = 0x1006 } + ctx.SelLine = 4 + end + lastGoodMenu = menuId + elseif (menuId==0x1001) then -- MODEL SETUP + local backId = 0xFFF9 -- No changes, just exit + local title = "Model Setup ("..MODEL.modelName..")" + if (menuDataChanged) then + backId = 0x1000 -- Go to Save menu + title = title.." *" + end + ctx.Menu = { MenuId = 0x1001, Text = title, PrevId = 0, NextId = 0, BackId = backId, TextId=0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, Text = "Aircraft Type Setup", ValId = 0x1010,TextId=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, Text = "Wing & Tail Channels ", ValId = 0x1020, TextId=0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text = "Gyro Channel Reverse", ValId = 0x1030, TextId=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text = "WARNING: Changing of Aircraft or Wing will", ValId = 0x1001, TextId=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text = "delete previous Channel/Port assigments.", ValId = 0x1001, TextId=0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1005) then + modelLib.printChannelSummary() + modelLib.ST_SaveFileData() + menuDataChanged = false + + + local msg1 = "Data saved to: " + local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt" + + ctx.Menu = { MenuId = 0x1005, Text = "Config Saved", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1005 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1005 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 } + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1006) then + modelLib.ST_LoadFileData() + menuDataChanged = false + currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] + currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE] + + local msg1 = "Data restored from: " + local msg2 = " "..DATA_PATH.."/"..modelLib.hashName(MODEL.modelName)..".txt" + + ctx.Menu = { MenuId = 0x1006, Text = "Discart Changes", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, Text=msg1, TextId = 0, ValId = 0x1006 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, Text=msg2, TextId = 0, ValId = 0x1006 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Complete", TextId = 0, ValId = 0xFFF9 } + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1010) then + modelLib.printChannelSummary() + ctx.Menu = { MenuId = 0x1010, Text = "Aircraft Type", PrevId = 0, NextId = 0x1011, BackId = 0x1001, TextId=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Aircraft Type", TextId = 0, ValId = MEMU_VAR.AIRCRAFT_TYPE, Min=50, Max=53, Def=50, Val=MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1011) then + ctx.Menu = { MenuId = 0x1011, Text = "Model Type:"..modelLib.aircraft_type_text[currAircraftType], PrevId = 0, NextId = 0x1020, BackId = 0x1010, TextId=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Wing Type", TextId = 0, ValId = MEMU_VAR.WING_TYPE, Min=100, Max=107, Def=100, Val=MENU_DATA[MEMU_VAR.WING_TYPE] } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, Text="Tail Type", TextId = 0, ValId = MEMU_VAR.TAIL_TYPE, Min=200, Max=210, Def=200, Val=MENU_DATA[MEMU_VAR.TAIL_TYPE] } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1020) then + ------ WING SETUP ------- + local thr = MENU_DATA[MEMU_VAR.CH_THR] + local leftAil = MENU_DATA[MEMU_VAR.CH_L_AIL] + local rightAil = MENU_DATA[MEMU_VAR.CH_R_AIL] + local leftFlap = MENU_DATA[MEMU_VAR.CH_L_FLP] + local rightFlap = MENU_DATA[MEMU_VAR.CH_R_FLP] + + local thrText = "Thr" + local leftAilText = "Left Aileron" + local rightAilText = "Right Aileron" + local leftFlapText = "Left Flap" + local rightFlapText = "Right Flap" + + if (rightAil==nil) then leftAilText = "Aileron" end + if (rightFlap==nil) then leftFlapText = "Flap" end + + local title = modelLib.aircraft_type_text[currAircraftType].." Wing:"..modelLib.wing_type_text[currWingType] + + ctx.Menu = { MenuId = 0x1020, Text = title, PrevId = 0, NextId = 0x1021, BackId = 0x1011, TextId=0 } + + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=thrText, TextId = 0, ValId = MEMU_VAR.CH_THR, Min=0, Max=10, Def=0, Val= thr } + + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftAilText, TextId = 0, ValId = MEMU_VAR.CH_L_AIL, Min=0, Max=9, Def=0, Val= leftAil } + + if (rightAil~=nil) then + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightAilText, TextId = 0, ValId = MEMU_VAR.CH_R_AIL, Min=0, Max=9, Def=0, Val= rightAil } + end + + if (leftFlap~=nil) then + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftFlapText, TextId = 0, ValId = MEMU_VAR.CH_L_FLP, Min=0, Max=9, Def=0, Val= leftFlap } + end + if (rightFlap~=nil) then + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightFlapText, TextId = 0, ValId = MEMU_VAR.CH_R_FLP, Min=0, Max=9, Def=0, Val= rightFlap } + end + + ctx.SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x1021) then + ------ TAIL SETUP ------- + local leftRud = MENU_DATA[MEMU_VAR.CH_L_RUD] + local rightRud = MENU_DATA[MEMU_VAR.CH_R_RUD] + local leftEle = MENU_DATA[MEMU_VAR.CH_L_ELE] + local rightEle = MENU_DATA[MEMU_VAR.CH_R_ELE] + + local leftRudText = "Left Rudder" + local rightRudText = "Right Rudder" + + local leftElvText = "Left Elevator" + local rightElvText = "Right Elevator" + + if (rightRud==nil) then leftRudText = "Rudder" end + if (rightEle==nil) then leftElvText = "Elevator" end + + local title = modelLib.aircraft_type_text[currAircraftType].." Tail:"..modelLib.tail_type_text[currTailType] + + ctx.Menu = { MenuId = 0x1021, Text = title, PrevId = 0, NextId = 0x1001, BackId = 0x1020, TextId=0 } + if (leftRud~=nil) then + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftRudText, TextId = 0, ValId = MEMU_VAR.CH_L_RUD, Min=0, Max=9, Def=0, Val= leftRud} + end + + if (rightRud~=nil) then + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightRudText, TextId = 0, ValId = MEMU_VAR.CH_R_RUD, Min=0, Max=9, Def=0, Val=rightRud } + end + + if (leftEle~=nil) then + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=leftElvText, TextId = 0, ValId = MEMU_VAR.CH_L_ELE, Min=0, Max=9, Def=0, Val=leftEle } + end + + if (rightEle~=nil) then + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, Text=rightElvText, TextId = 0, ValId = MEMU_VAR.CH_R_ELE, Min=0, Max=9, Def=0, Val=rightEle } + end + + ctx.SelLine = 1 + lastGoodMenu = menuId + + elseif (menuId==0x1030) then + modelLib.CreateDSMPortChannelInfo() + modelLib.printChannelSummary() + + ctx.Menu = { MenuId = 0x1030, Text = "Gyro Channel Reverse (Port 1-5)", PrevId = 0, NextId = 0x1031, BackId = 0x1001, TextId=0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT1), TextId = 0, ValId = MEMU_VAR.PORT1_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT1_MODE], Format = formatTXRevert(PORT.PORT1) } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT2), TextId = 0, ValId = MEMU_VAR.PORT2_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT2_MODE], Format = formatTXRevert(PORT.PORT2) } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT3), TextId = 0, ValId = MEMU_VAR.PORT3_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT3_MODE], Format = formatTXRevert(PORT.PORT3) } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT4), TextId = 0, ValId = MEMU_VAR.PORT4_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT4_MODE], Format = formatTXRevert(PORT.PORT4) } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT5), TextId = 0, ValId = MEMU_VAR.PORT5_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT5_MODE], Format = formatTXRevert(PORT.PORT5) } + + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1030 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1030 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1031) then + modelLib.CreateDSMPortChannelInfo() + modelLib.printChannelSummary() + ctx.Menu = { MenuId = 0x1031, Text = "Gyro Channel Reverse (Port 6-10)", PrevId = 0x1030, NextId = 0, BackId = 0x1001, TextId=0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT6), TextId = 0, ValId = MEMU_VAR.PORT6_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT6_MODE], Format = formatTXRevert(PORT.PORT6) } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT7), TextId = 0, ValId = MEMU_VAR.PORT7_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT7_MODE], Format = formatTXRevert(PORT.PORT7) } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT8), TextId = 0, ValId = MEMU_VAR.PORT8_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT8_MODE], Format = formatTXRevert(PORT.PORT8) } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT9), TextId = 0, ValId = MEMU_VAR.PORT9_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT9_MODE], Format = formatTXRevert(PORT.PORT9) } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, Text=Header(PORT.PORT10), TextId = 0, ValId = MEMU_VAR.PORT10_MODE, Min=300, Max=301, Def=300, Val=MENU_DATA[MEMU_VAR.PORT10_MODE], Format = formatTXRevert(PORT.PORT10) } + + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, Text="Only Thr/Ail/Rud/Ele. This affects AS3X/SAFE reaction dir./b", TextId = 0, ValId = 0x1031 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, Text="Any changes, use RX 'Relearn Servo Settings'/b", TextId = 0, ValId = 0x1031 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + else + print("NOT IMPLEMENTED") + ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = menuLib.BACK_BUTTON + end + + menuLib.PostProcessMenu() +end + +-- ST_SendReceive +-- Main state machine for the Setup menu + +local function ST_SendReceive() + local ctx = menuLib.DSM_Context + --if (DEBUG_ON>1) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + + if ctx.Phase == PHASE.RX_VERSION then -- request RX version + ctx.RX.Name = "MODEL SETUP" + ctx.RX.Version = SETUP_LIB_VERSION + ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId = 0x01001 + + ctx.Refresh_Display = true + + + elseif ctx.Phase == PHASE.WAIT_CMD then + + elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title + ST_LoadMenu(ctx.Menu.MenuId) + ctx.Phase = PHASE.WAIT_CMD + ctx.Refresh_Display = true + + elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + + if (MENU_DATA[line.ValId] ~= line.Val ) then + MENU_DATA[line.ValId] = line.Val + print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val)) + menuDataChanged=true + end + + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + + elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then + local line = ctx.MenuLines[ctx.SelLine] + + elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + + -- Update the menu data from the line + if (MENU_DATA[line.ValId] ~= line.Val ) then + MENU_DATA[line.ValId] = line.Val + print(string.format("MENU_DATA[%d/%s]=%d",line.ValId,line.Text, line.Val)) + menuDataChanged=true + end + + -- Did the aircraft type change? + if (currAircraftType ~= MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE]) then + currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] + modelLib.ST_AircraftInit(currAircraftType) + currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE] + end + + -- Did the Wing type change? + if (currWingType ~= MENU_DATA[MEMU_VAR.WING_TYPE]) then + if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then + currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + modelLib.ST_GliderWingInit(currWingType) + else + currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + modelLib.ST_PlaneWingInit(currWingType) + + end + + -- DELTA has only RUDER + if ((currWingType==WING_TYPE.ELEVON_A or currWingType==WING_TYPE.ELEVON_B) and TAIL_TYPE~=TAIL_TYPE.RUD_1) then + MENU_DATA[MEMU_VAR.TAIL_TYPE] = TAIL_TYPE.RUD_1 + end + end + + --- Did the tail changed? + local ntt = MENU_DATA[MEMU_VAR.TAIL_TYPE] + if (currTailType ~= ntt) then + if (currAircraftType==AIRCRAFT_TYPE.GLIDER) then + currTailType = ntt + modelLib.ST_GliderTailInit(currTailType) + else + if (not tailTypeCompatible(currTailType,ntt)) then + modelLib.ST_PlaneTailInit(ntt) + end + currTailType = ntt + end + end + + ctx.Phase = PHASE.WAIT_CMD + elseif ctx.Phase == PHASE.EXIT then + ctx.Phase=PHASE.EXIT_DONE + end +end + +------------------------------------------------------------------------------------------------------------ + +-- Inital List and Image Text for this menus +local function ST_Init_Text(rxId) + menuLib.clearAllText() + + local List_Values = menuLib.List_Values + local List_Text = menuLib.List_Text + local Text = menuLib.Text + local List_Text_Img = menuLib.List_Text_Img + + -- Channel Names use the Port Text Retrived from OTX/ETX + for i = 0, 9 do List_Text[i] = MODEL.PORT_TEXT[i] end + List_Text[10]="--" + + -- Aircraft Type + List_Text[50+AIRCRAFT_TYPE.PLANE] = "Airplane"; --List_Text_Img[50+AIRCRAFT_TYPE.PLANE] = "at_plane.png|Airplane" + List_Text[50+AIRCRAFT_TYPE.GLIDER] = "Glider (Partial work)"; --List_Text_Img[50+AIRCRAFT_TYPE.GLIDER] = "at_glider.png|Glider" + List_Text[50+AIRCRAFT_TYPE.HELI] = "Helicopter (Not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.HELI] = "at_heli.png|Helicopter" + List_Text[50+AIRCRAFT_TYPE.DRONE] = "Drone (not done)"; --List_Text_Img[50+AIRCRAFT_TYPE.DRONE] = "at_drone.png|Drone" + + -- Wing Types + List_Text[100+WING_TYPE.AIL_1] = "Single Ail"; List_Text_Img[100+WING_TYPE.AIL_1] = "wt_1ail.png|Single Aileron" + List_Text[100+WING_TYPE.AIL_2] = "Dual Ail"; List_Text_Img[100+WING_TYPE.AIL_2] = "wt_2ail.png|Dual Aileron" + List_Text[100+WING_TYPE.FLAPERON] = "Flaperon"; List_Text_Img[100+WING_TYPE.FLAPERON] = "wt_flaperon.png|Flaperon" + List_Text[100+WING_TYPE.AIL_1_FLP_1] = "Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_1_FLP_1] = "wt_1ail_1flp.png|Aileron + Flap" + List_Text[100+WING_TYPE.AIL_2_FLP_1] = "Dual Ail + Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_1] = "wt_2ail_1flp.png|Dual Aileron + Flap" + List_Text[100+WING_TYPE.AIL_2_FLP_2] = "Dual Ail + Dual Flap"; List_Text_Img[100+WING_TYPE.AIL_2_FLP_2] = "wt_2ail_2flp.png|Dual Aileron + Dual Flap" + List_Text[100+WING_TYPE.ELEVON_A] = "Delta/Elevon A"; List_Text_Img[100+WING_TYPE.ELEVON_A] = "wt_elevon.png|Delta/Elevon A" + List_Text[100+WING_TYPE.ELEVON_B] = "Delta/Elevon B"; List_Text_Img[100+WING_TYPE.ELEVON_B] = "wt_elevon.png|Delta/Elevon B" + + -- Tail Types + List_Text[200+TAIL_TYPE.RUD_1] = "Rudder Only"; List_Text_Img[200+TAIL_TYPE.RUD_1] = "tt_1rud.png|Rudder Only" + List_Text[200+TAIL_TYPE.RUD_1_ELEV_1] = "Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_1] = "tt_1rud_1ele.png|Tail Normal" + List_Text[200+TAIL_TYPE.RUD_1_ELEV_2] = "Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_1_ELEV_2] = "tt_1rud_2ele.png|Rud + Dual Elev" + List_Text[200+TAIL_TYPE.RUD_2_ELEV_1] = "Dual Rud + Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_1] = "tt_2rud_1ele.png|Dual Rud + Elev" + List_Text[200+TAIL_TYPE.RUD_2_ELEV_2] = "Dual Rud + Dual Ele"; List_Text_Img[200+TAIL_TYPE.RUD_2_ELEV_2] = "tt_2rud_2ele.png|Dual Rud + Dual Elev" + List_Text[200+TAIL_TYPE.VTAIL_A] = "V-Tail A"; List_Text_Img[200+TAIL_TYPE.VTAIL_A] = "tt_vtail.png|V-Tail A" + List_Text[200+TAIL_TYPE.VTAIL_B] = "V-Tail B"; List_Text_Img[200+TAIL_TYPE.VTAIL_B] = "tt_vtail.png|V-Tail B" + List_Text[200+TAIL_TYPE.TRAILERON_A] = "Taileron A"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A] = "tt_taileron.png|Taileron A" + List_Text[200+TAIL_TYPE.TRAILERON_B] = "Taileron B"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B] = "tt_taileron.png|Taileron B" + List_Text[200+TAIL_TYPE.TRAILERON_A_R2] = "Taileron A + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_A_R2] = "tt_taileron2.png|Taileron A + Dual Rud" + List_Text[200+TAIL_TYPE.TRAILERON_B_R2] = "Taileron B + 2x Rud"; List_Text_Img[200+TAIL_TYPE.TRAILERON_B_R2] = "tt_taileron2.png|Taileron B + Dual Rud" + + + -- Servo Reverse + if (LCD_W > 128) then + List_Text[300+CH_MODE_TYPE.NORMAL] = "Normal " + List_Text[300+CH_MODE_TYPE.REVERSE] = "Reverse" + else + List_Text[300+CH_MODE_TYPE.NORMAL] = "Nor" + List_Text[300+CH_MODE_TYPE.REVERSE] = "Rev" + end +end + +-- Initial Setup +local function ST_Init() + -- Initialize text (use RX_ID 0) + ST_Init_Text(0) + + -- Setup default Data, and load a file if exist + --modelLib.ST_Default_Data() + if (modelLib.ST_LoadFileData()==0) then -- Did not load a file + modelLib.ST_Default_Data() + modelLib.ST_SaveFileData() -- Save Defaults + end + menuDataChanged = false + currAircraftType = MENU_DATA[MEMU_VAR.AIRCRAFT_TYPE] + currWingType = MENU_DATA[MEMU_VAR.WING_TYPE] + currTailType = MENU_DATA[MEMU_VAR.TAIL_TYPE] + + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.RX_VERSION +end + +local function ST_Done() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.EXIT_DONE +end + + +return { init=ST_Init, run=ST_SendReceive, done=ST_Done } \ No newline at end of file diff --git a/SCRIPTS/TOOLS/DSMLIB/DsmSimMenuLib.lua b/SCRIPTS/TOOLS/DSMLIB/DsmSimMenuLib.lua new file mode 100644 index 0000000..43d45d1 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/DsmSimMenuLib.lua @@ -0,0 +1,1596 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- This script simulates the Forward programming menus for AR631 and FC6250HX +-- receivers. +-- The intend is to make easier GUI development in Companion since it cannot +-- talk to the receivers +-- +-- Author: Francisco Arzu +------------------------------------------------------------------------------ + + +local Log, menuLib, modelLib, DEBUG_ON = ... -- Get DebugON from parameters +local SIM_LIB_VERSION = "0.56" +local MSG_FILE = "/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt" + +local PHASE = menuLib.PHASE +local LINE_TYPE = menuLib.LINE_TYPE + +local SimLib = {} + +local lastGoodMenu=0 +local RX_loadMenu = nil +local RX_Initialized = true + +local IS_EDGETX = false + + +local function AR631_loadMenu(menuId) + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context + + if (menuId==0x1000) then + --M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"] + --L[#0 T=M VId=0x1010 Text="Gyro settings" MId=0x1000 ] + --L[#1 T=M VId=0x105E Text="Other settings" MId=0x1000 ] + + ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x00F9, ValId = 0x1010 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x0227, ValId = 0x105E } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1010) then + -- M[Id=0x1010 P=0x0 N=0x0 B=0x1000 Text="Gyro settings"] + + -- NEW + -- L[#5 T=M VId=0x104F val=nil [0->0,3] Text="First Time Setup" MId=0x1010 ] -- NEW ONLY + -- L[#6 T=M VId=0x1055 Text="First Time SAFE Setup"[0x20D] MId=0x1010 ] + + -- Initialize AR637T + -- L[#0 T=M VId=0x1011 Text="AS3X Settings"[0x1DD] MId=0x1010 ] + -- L[#1 T=M VId=0x1019 Text="SAFE Settings"[0x1E2] MId=0x1010 ] + -- L[#2 T=M VId=0x1021 Text="F-Mode Setup"[0x87] MId=0x1010 ] + -- L[#3 T=M VId=0x1022 Text="System Setup"[0x86] MId=0x1010 ] + -- Only on BNF locked receivers + -- L[#4 T=M VId=0x105C Text="SAFE Select "[0x1F9] MId=0x1010 ] + + + ctx.Menu = { MenuId = 0x1010, TextId = 0x00F9, PrevId = 0, NextId = 0, BackId = 0x1000 } + if not RX_Initialized then + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x00A5, ValId = 0x104F} + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x020D, ValId = 0x1055} + ctx.SelLine = 5 + else + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x01DD, ValId = 0x1011 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x01E2, ValId = 0x1019 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0087, ValId = 0x1021 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0086, ValId = 0x1022 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x01F9, ValId = 0x105C } + ctx.SelLine = 0 + end + lastGoodMenu = menuId + elseif (menuId==0x1011) then + -- M[Id=0x1011 P=0x0 N=0x0 B=0x1010 Text="AS3X Settings"[0x1DD]] + -- L[#0 T=M VId=0x1012 Text="AS3X Gains"[0x1DE] MId=0x1011 ] + -- L[#1 T=M VId=0x1013 Text="Priority"[0x46] MId=0x1011 ] + + -- L[#2 T=M VId=0x1015 Text="Heading"[0x82] MId=0x1011 ] + -- L[#4 T=LM VId=0x1004 val=50 [0->244,50,TS=0] Text="Gain Sensitivity"[0x8A] MId=0x1011] + -- L[#5 T=M VId=0x1016 Text="Fixed/Adjustable Gains"[0x263] MId=0x1011 ] + -- L[#6 T=M VId=0x1017 Text="Capture Gyro Gains"[0xAA] MId=0x1011 ] + + ctx.Menu = { MenuId = 0x1011, TextId = 0x1DD, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x1DE, ValId = 0x1012} + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x46, ValId = 0x1013} + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x82, ValId = 0x1015} + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x8A, ValId = 0x1004, Min=0, Max=244, Def=50, Val=50 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x1016} + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1017 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1012) then + -- M[Id=0x1012 P=0x0 N=0x0 B=0x1011 Text="AS3X Gains"[0x1DE]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1012 ] + --L[#2 T=M VId=0x1012 Text="Rate Gains"[0x1E0] MId=0x1012 ] + --L[#3 T=V_nc VId=0x1004 Text="Roll"[0x40] val=14 [0->100,40] MId=0x1012 ] + --L[#4 T=V_nc VId=0x1005 Text="Pitch"[0x41] val=29 [0->100,50] MId=0x1012 ] + --L[#5 T=V_nc VId=0x1006 Text="Yaw"[0x42] val=48 [0->100,60] MId=0x1012 ] + + ctx.Menu = { MenuId = 0x1012, TextId = 0x1DE, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x1E0, ValId = 0x1012 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x40, ValId = 0x1004, Min=0, Max=100, Def=40, Val=40 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x41, ValId = 0x1005, Min=0, Max=100, Def=50, Val=50 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x42, ValId = 0x1006, Min=0, Max=100, Def=60, Val=60 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1013) then + --M[Id=0x1013 P=0x0 N=0x0 B=0x1011 Text="Priority"[0x46]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1012 ] + --L[#1 T=M VId=0x1013 Text="Stick Priority"[0xFE] MId=0x1013 ] + --L[#3 T=V_nc VId=0x1004 Text="Roll"[0x40] val=14 [0->160,160] MId=0x1012 ] + --L[#4 T=V_nc VId=0x1005 Text="Pitch"[0x41] val=29 [0->160,160] MId=0x1012 ] + --L[#5 T=V_nc VId=0x1006 Text="Yaw"[0x42] val=48 [0->160,160] MId=0x1012 ] + + ctx.Menu = { MenuId = 0x1013, TextId = 0x46, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xFE, ValId = 0x1013 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x40, ValId = 0x1004, Min=0, Max=160, Def=100, Val=160 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x41, ValId = 0x1005, Min=0, Max=160, Def=100, Val=160 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x42, ValId = 0x1006, Min=0, Max=160, Def=100, Val=160 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1015) then + -- M[Id=0x1015 P=0x0 N=0x0 B=0x1011 Text="Heading Gain"[0x266]] + -- L[#0T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1015 ] + -- L[#1 T=M VId=0x1015 Text="Heading Gain"[0x266] MId=0x1015 ] + -- L[#2 T=V_nc VId=0x1004 Text="Roll"[0x40] val=0 [0->100,0] MId=0x1015 ] + -- L[#3 T=V_nc VId=0x1005 Text="Pitch"[0x41] val=0 [0->100,0] MId=0x1015 ] + -- L[#5 T=M VId=0x1015 Text="Use CAUTION for Yaw gain!"[0x26A] MId=0x1015 ] + -- L[#6T=V_nc VId=0x1006 Text="Yaw"[0x42] val=0 [0->100,0] MId=0x1015 ] + + ctx.Menu = { MenuId = 0x1015, TextId = 0x266, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x1F9, ValId = 0x1015 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x40, ValId = 0x1004, Min=0, Max=100, Def=0, Val=0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x41, ValId = 0x1005, Min=0, Max=100, Def=0, Val=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x26A, ValId = 0x1015 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x42, ValId = 0x1006, Min=0, Max=100, Def=0, Val=0 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1016) then + -- M[Id=0x1016 P=0x0 N=0x0 B=0x1011 Text="Fixed/Adjustable Gains"[0x263]] + -- L[#0T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1016 ] + -- L[#1 T=M VId=0x1016 val=nil [0->0,2] Text="Fixed/Adjustable Gains"[0x263] MId=0x1016 ] + -- L[#2 T=LM_nc VId=0x1002 Text="Roll"[0x40] MId=0x1016 val=1 NL=(0->1,24,S=242) [242->243,243] ] + -- L[#3 T=LM_nc VId=0x1003 Text="Pitch"[0x41] MId=0x1016 val=1 NL=(0->1,1,S=242) [242->243,243] ] + -- L[#4 T=LM_nc VId=0x1004 Text="Yaw"[0x42] MId=0x1016 val=1 NL=(0->1,1,S=242) [242->243,243] ] + + ctx.Menu = { MenuId = 0x1016, TextId = 0x263, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x1F9, ValId = 0x1016 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x40, ValId = 0x1002, Min=242, Max=243, Def=243, Val=1 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x41, ValId = 0x1003, Min=242, Max=243, Def=243, Val=1 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x42, ValId = 0x1004, Min=242, Max=243, Def=243, Val=1 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1017) then + --M[Id=0x1017 P=0x0 N=0x0 B=0x1011 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1017 Text="Gains will be captured on"[0x24C] MId=0x1017 ] + --L[#1 T=V_nc VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1017 ] + --L[#2 T=M VId=0x1017 Text="Captured gains will be"[0x24D] MId=0x1017 ] + --L[#3 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1017 ] + --L[#4 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1017 ] + --L[#5 T=V_i8 VId=0x1006 Text="Yaw"[0x42] Val=60 [0->0,0] MId=0x1017 ] + --L[#6 T=M VId=0x1018 Text="Capture Gyro Gains"[0xAA] MId=0x1017 ] + + ctx.Menu = { MenuId = 0x1017, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x24C, ValId = 0x1017 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x24D, ValId = 0x1017 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=40 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=50 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x1006, Min=0, Max=0, Def=0, Val=60 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1018 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1018) then + --M[Id=0x1018 P=0x0 N=0x0 B=0x1011 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1018 Text="Gains on"[0x24E] MId=0x1018 ] + --L[#1 T=V_nc VId=0x1018 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1018 ] + --L[#2 T=M VId=0x1018 Text="were captured and changed"[0x24F] MId=0x1018 + --L[#3 T=M VId=0x1018 Text="from Adjustable to Fixed"[0x250] MId=0x1018 ] + --L[#4 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1018 ] + --L[#5 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1018 ] + --L[#6 T=V_i8 VId=0x1006 Text="Yaw"[0x42] Val=60 [0->0,0] MId=0x1018 ] + + ctx.Menu = { MenuId = 0x1018, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1011 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x24E, ValId = 0x1018 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x24F, ValId = 0x1018 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x250, ValId = 0x1018 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=40 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=50 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x1006, Min=0, Max=0, Def=0, Val=60 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x1019) then + --M[Id=0x1019 P=0x0 N=0x0 B=0x1010 Text="SAFE Settings"[0x1E2]] + --L[#0 T=M VId=0x101A Text="SAFE Gains"[0x1E3] MId=0x1019 ] + --L[#1 T=M VId=0x101B Text="Angle Limits"[0x226] MId=0x1019 ] + --L[#5 T=M VId=0x101E Text="Fixed/Adjustable Gains"[0x263] MId=0x1019 ] + --L[#6 T=M VId=0x101F Text="Capture Gyro Gains"[0xAA] MId=0x1019 ] + + ctx.Menu = { MenuId = 0x1019, TextId = 0x1E2, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x1E3, ValId = 0x101A } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x226, ValId = 0x101B } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x101E } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x101F } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x101A) then + --M[Id=0x101A P=0x0 N=0x0 B=0x1019 Text="SAFE Gains"[0x1E3]] + --L[#0 T=V_nc VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101A ] + --L[#1 T=M VId=0x101A Text="Gain"[0x43] MId=0x101A ] + --L[#2 T=V_nc VId=0x1002 Text="Roll"[0x40] Val=35 [5->100,35] MId=0x101A ] + --L[#3 T=V_nc VId=0x1003 Text="Pitch"[0x41] Val=35 [5->100,35] MId=0x101A ] + + ctx.Menu = { MenuId = 0x101A, TextId = 0x1E3, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x43, ValId = 0x101A } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x40, ValId = 0x1002, Min=5, Max=100, Def=35, Val=35 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x41, ValId = 0x1003, Min=5, Max=100, Def=60, Val=35 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x101B) then + --M[Id=0x101B P=0x0 N=0x0 B=0x1019 Text="Angle Limits"[0x226]] + --L[#0T=V_nc VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101B ] + --L[#1 T=M VId=0x101B Text="Angle Limits"[0x226] MId=0x101B ] + --L[#2 T=V_nc VId=0x1002 Text="Roll Right"[0x1E9] Val=60 [10->90,60] MId=0x101B ] + --L[#3 T=V_nc VId=0x1003 Text="Roll Left"[0x1EA] Val=60 [10->90,60] MId=0x101B ] + --L[#4 T=V_nc VId=0x1004 Text="Pitch Down"[0x1EB] Val=40 [10->75,40] MId=0x101B ] + --L[#5 T=V_nc VId=0x1005 Text="Pitch Up"[0x1EC] Val=50 [10->75,50] MId=0x101B ] + + ctx.Menu = { MenuId = 0x101B, TextId = 0x226, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x226, ValId = 0x101B } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1E9, ValId = 0x1002, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EA, ValId = 0x1003, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EB, ValId = 0x1004, Min=10, Max=90, Def=40, Val=40 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EC, ValId = 0x1005, Min=10, Max=90, Def=50, Val=50 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + + elseif (menuId==0x101E) then + --M[Id=0x101E P=0x0 N=0x0 B=0x1019 Text="Fixed/Adjustable Gains"[0x263]] + --L[#0 T=V_nc VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=nil [0->10,0] MId=0x101E ] + --L[#1 T=M VId=0x101E Text="Fixed/Adjustable Gains"[0x263] MId=0x101E ] + --L[#2 T=LM_nc VId=0x1002 Text="Roll"[0x40] Val=0 N=(0->1,1,S=242) [242->243,243] MId=0x101E ] + --L[#3 T=LM_nc VId=0x1003 Text="Pitch"[0x41] Val=0 N=(0->1,1,S=242) [242->243,243] MId=0x101E ] + + ctx.Menu = { MenuId = 0x101E, TextId = 0x263, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x263, ValId = 0x101E } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x40, ValId = 0x1002, Min=242, Max=243, Def=243, Val=0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x41, ValId = 0x1003, Min=242, Max=243, Def=243, Val=0 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x101F) then + --M[Id=0x101F P=0x0 N=0x0 B=0x1019 Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x101F Text="Gains will be captured on"[0x24C] MId=0x101F ] + --L[#1 T=V_nc VId=0x1000 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x101F ] + --L[#2 T=M VId=0x101F Text="Captured gains will be"[0x24D] MId=0x101F ] + --L[#3 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x101F ] + --L[#4 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x101F ] + --L[#6 T=M VId=0x1020 Text="Capture Gyro Gains"[0xAA] MId=0x101F ] + + ctx.Menu = { MenuId = 0x101F, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x24C, ValId = 0x101F } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x24D, ValId = 0x101F } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0xAA, ValId = 0x1020 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1020) then + --M[Id=0x1020 P=0x0 N=0x0 B=0x101F Text="Capture Gyro Gains"[0xAA]] + --L[#0 T=M VId=0x1020 Text="Gains on"[0x24E] MId=0x1020 ] + --L[#1 T=V_nc VId=0x1018 Text=" Flight Mode 1"[0x8001] Val=1 [0->10,0] MId=0x1020 ] + --L[#2 T=M VId=0x1018 Text="were captured and changed"[0x24F] MId=0x1020 + --L[#3 T=M VId=0x1018 Text="from Adjustable to Fixed"[0x250] MId=0x1020 ] + --L[#4 T=V_i8 VId=0x1004 Text="Roll"[0x40] Val=40 [0->0,0] MId=0x1020 ] + --L[#5 T=V_i8 VId=0x1005 Text="Pitch"[0x41] Val=50 [0->0,0] MId=0x1020 ] + + ctx.Menu = { MenuId = 0x1020, TextId = 0xAA, PrevId = 0, NextId = 0, BackId = 0x1019 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x24E, ValId = 0x1020 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x24F, ValId = 0x1020 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x250, ValId = 0x1020 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x40, ValId = 0x1004, Min=0, Max=0, Def=0, Val=35 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x41, ValId = 0x1005, Min=0, Max=0, Def=0, Val=35 } + + ctx.SelLine = -1 + lastGoodMenu = menuId + elseif (menuId==0x1021) then + --M[Id=0x1021 P=0x0 N=0x0 B=0x1010 Text="F-Mode Setup"[0x87]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x1021 ] + --L[#1 T=M VId=0x7CA6 Text="FM Channel"[0x78] MId=0x1021 ] + --L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] val=1 (0->1,3,S=3) [3->4|3] MId=0x1021] + + -- Why Jump from Value 3 to 176?? where do we know valid values???? + --L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] val=3|"Inh" NL=(0->244,0,S=0) [0->244,3] MId=0x1021 ] + --L[#3 T=LM VId=0x1003 Text="Safe Mode"[0x1F8] val=176|"Self-Level/Angle Dem" NL=(0->244,0,S=0) [0->244,3] MId=0x1021 ] + + --L[#4 T=LM VId=0x1004 Text="Panic"[0x8B] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + --L[#5 T=LM VId=0x1005 Text="High Thr to Pitch"[0x1F0] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + --L[#6 T=LM VId=0x1006 Text="Low Thr to Pitch"[0x1EF] val=0 NL=(0->1,3,S=3) [3->4,3] MId=0x1021 ] + + ctx.Menu = { MenuId = 0x1021, TextId = 0x87, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x78, ValId = 0x7CA6 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1DC, ValId = 0x1002, Min=3, Max=4, Def=3, Val=1 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1F8, ValId = 0x1003, Min=0, Max=244, Def=3, Val=176 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x8B, ValId = 0x1004, Min=3, Max=4, Def=3, Val=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1F0, ValId = 0x1005, Min=3, Max=4, Def=3, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1EF, ValId = 0x1006, Min=3, Max=4, Def=3, Val=0 } + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1022) then + --M[Id=0x1022 P=0x0 N=0x0 B=0x1010 Text="System Setup"[0x86]] + --L[#0 T=M VId=0x1023 Text="Relearn Servo Settings"[0x190] MId=0x1022 ] + --L[#1 T=M VId=0x1025 Text="Orientation"[0x80] MId=0x1022 ] + --L[#2 T=M VId=0x1029 Text="Gain Channel Select"[0xAD] MId=0x1022 ] + --L[#3 T=M VId=0x102A Text="SAFE/Panic Mode Setup"[0xCA] MId=0x1022 ] + --L[#4 T=M VId=0x1032 Text="Utilities"[0x240] MId=0x1022 ] + + ctx.Menu = { MenuId = 0x1022, TextId = 0x86, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x190, ValId = 0x1023 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x80, ValId = 0x1025 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xAD, ValId = 0x1029 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xCA, ValId = 0x102A } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x240, ValId = 0x1032 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1023) then + --M[Id=0x1023 P=0x0 N=0x0 B=0x1022 Text="Relearn Servo Settings"[0x190]] + --L[#3 T=M VId=0x1024 Text="Apply"[0x90] MId=0x1023 ] + + ctx.Menu = { MenuId = 0x1023, TextId = 0x190, PrevId = 0, NextId = 0, BackId = 0x1022 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1024 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1024) then + --M[Id=0x1024 P=0x0 N=0x0 B=0x0 Text="Relearn Servo Settings"[0x190]] + --L[#3 T=M VId=0x1000 Text="Complete"[0x93] MId=0x1024 ] + + ctx.Menu = { MenuId = 0x1024, TextId = 0x190, PrevId = 0, NextId = 0, BackId = 0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1000 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + + elseif (menuId==0x1025) then + --M[Id=0x1025 P=0x0 N=0x0 B=0x1022 Text="Orientation"[0x80]] + --L[#0 T=M VId=0x1025 Text="Set the model level,"[0x21A] MId=0x1025 ] + --L[#1 T=M VId=0x1025 Text="and press Continue."[0x21B] MId=0x1025 ] + --L[#2 T=M VId=0x1025 Text=""[0x21C] MId=0x1025 ] + --L[#3 T=M VId=0x1025 Text=""[0x21D] MId=0x1025 ] + --L[#5 T=M VId=0x1026 Text="Continue"[0x224] MId=0x1025 ] + --L[#6 T=M VId=0x1027 Text="Set Orientation Manually"[0x229] MId=0x1025 ] + + ctx.Menu = { MenuId = 0x1025, TextId = 0x80, PrevId = 0, NextId = 0, BackId = 0x1022 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x21A, ValId = 0x1025 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x21B, ValId = 0x1025 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x21C, ValId = 0x1025 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x21D, ValId = 0x1025 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1026 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x229, ValId = 0x1027 } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1026) then + --M[Id=0x1026 P=0x1025 N=0x0 B=0x1025 Text="Orientation"[0x80]] + --L[#0 T=M VId=0x1026 Text="Set the model on its nose,"[0x21F] MId=0x1026 ] + --L[#1 T=M VId=0x1026 Text="and press Continue. If the"[0x220] MId=0x1026 ] + --L[#2 T=M VId=0x1026 Text="orientation on the next"[0x221] MId=0x1026 ] + --L[#3 T=M VId=0x1026 Text="screen is wrong go back"[0x222] MId=0x1026 ] + --L[#4 T=M VId=0x1026 Text="and try again."[0x223] MId=0x1026 ] + --L[#6 T=M VId=0x1027 Text="Continue"[0x224] MId=0x1026 ] + + ctx.Menu = { MenuId = 0x1026, TextId = 0x80, PrevId = 0x1025, NextId = 0, BackId = 0x1025 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x21F, ValId = 0x1026 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x220, ValId = 0x1026 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x221, ValId = 0x1026 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x222, ValId = 0x1026 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x223, ValId = 0x1026 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1027 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1027) then + --M[Id=0x1028 P=0x0 N=0x0 B=0x1028 Text="Orientation"[0x80]] + --L[#5 T=LM_nc VId=0x1000 Text="Orientation"[0x80] Val=4|"RX Pos 5" NL=(0->23,0,S=203) [203->226,203] MId=0x1027 ] + --L[#6 T=M VId=0x1028 Text="Continue"[0x224] MId=0x1027 ] + + ctx.Menu = { MenuId = 0x1027, TextId = 0x80, PrevId = 0x1025, NextId = 0, BackId = 0x1025 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x80, ValId = 0x1000, Min=203, Max=226, Def=203, Val=5 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1028 } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1028) then + --M[Id=0x1027 P=0x1025 N=0x0 B=0x1025 Text="Orientation"[0x80]] + --L[#2 T=M VId=0x1 Text="Resetting RX... "[0x9F] MId=0x1028 ] + --L[#3 T=M VId=0x1028 Text="RX Pos 7"[0xD1] MId=0x1028 ] + + ctx.Menu = { MenuId = 0x1028, TextId = 0x80, PrevId = 0x1025, NextId = 0, BackId = 0x1025 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x9F, ValId = 0x1 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xD1, ValId = 0x1028 } + ctx.SelLine = 2 + lastGoodMenu = menuId + + elseif (menuId==0x1029) then + --M[Id=0x1029 P=0x0 N=0x0 B=0x1022 Text="Gain Channel Select"[0xAD]] + --L[#0 T=M VId=0x1029 Text="AS3X"[0x1DC] MId=0x1029 ] + --L[#1 T=LM VId=0x1000 Text="Roll"[0x40] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x1029 ] + --L[#2 T=LM VId=0x1001 Text="Pitch"[0x41] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x1029 ] + --L[#3 T=LM VId=0x1002 Text="Yaw"[0x42] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x1029 ] + --L[#4 T=M VId=0x1029 Text="SAFE"[0xDA] MId=0x1029 ] + --L[#5 T=LM VId=0x1004 Text="Roll"[0x40] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x1029 ] + --L[#6 T=LM VId=0x1005 Text="Pitch"[0x41] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x1029 ] + + ctx.Menu = { MenuId = 0x1029, TextId = 0xAD, PrevId = 0, NextId = 0, BackId = 0x1022 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x1DC, ValId = 0x1029 } + + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x40, ValId = 0x1000, Min=53, Max=85, Def=53, Val=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x41, ValId = 0x1001, Min=53, Max=85, Def=53, Val=0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x42, ValId = 0x1002, Min=53, Max=85, Def=53, Val=0 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1029 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x40, ValId = 0x1004, Min=53, Max=85, Def=53, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x41, ValId = 0x1005, Min=53, Max=85, Def=53, Val=0 } + + ctx.SelLine = 2 + lastGoodMenu = menuId + elseif (menuId==0x1030) then + --M[Id=0x1030 P=0x0 N=0x0 B=0x102A Text="Attitude Trim"[0x1E6]] + --L[#0 T=M VId=0x1030 Text="Level model and capture attiude/M"[0xCD] MId=0x1030 ] FORCED MENU + --L[#1 T=M VId=0x1030 Text="Attitude Trim"[0x1E6] MId=0x1030 ] + --L[#2 T=V_de VId=0x1002 Text="Roll"[0x40] Val=-1 [-45->45,0] MId=0x1030 ] + --L[#3 T=V_de VId=0x1003 Text="Pitch"[0x41] Val=7 [-45->45,0] MId=0x1030 ] + --L[#5 T=M VId=0x1030 Text="Positive = Nose Up/Roll Right"[0x267] MId=0x1030 ] + --L[#6 T=M VId=0x1030 Text="Negative = Nose Down/Roll Left"[0x268] MId=0x1030 ] + + ctx.Menu = { MenuId = 0x1030, TextId = 0x1E6, PrevId = 0, NextId = 0, BackId = 0x102A } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xCD, ValId = 0x1030 } -- FORCED MENU (/M) + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x1E6, ValId = 0x1030 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x40, ValId = 0x1002, Min=-45, Max=45, Def=0, Val=-1 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x41, ValId = 0x1003, Min=-45, Max=45, Def=0, Val=7 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x267, ValId = 0x1030 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x268, ValId = 0x1030 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1031) then + --M[Id=0x1031 P=0x0 N=0x0 B=0x102A Text="Failsafe Angles"[0x1F6]] + --L[#0 T=M VId=0x1031 Text="Failsafe Angles"[0x1F6] MId=0x1031 ] + --L[#1 T=V_de VId=0x1001 Text="Roll"[0x40] Val=0 [-90->90,0] MId=0x1031 ] + --L[#2 T=V_de VId=0x1002 Text="Pitch"[0x41] Val=0 [-90->90,0] MId=0x1031 ] + --L[#5 T=M VId=0x1031 Text="Positive = Nose Up/Roll Right"[0x267] MId=0x1031 ] + --L[#6 T=M VId=0x1031 Text="Negative = Nose Down/Roll Left"[0x268] MId=0x1031 ] + + ctx.Menu = { MenuId = 0x1031, TextId = 0x1F6, PrevId = 0, NextId = 0, BackId = 0x102A } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x1F6, ValId = 0x1031 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x40, ValId = 0x1001, Min=-90, Max=90, Def=0, Val=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x41, ValId = 0x1002, Min=-90, Max=90, Def=0, Val=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x267, ValId = 0x1031 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x268, ValId = 0x1031 } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1032) then + --M[Id=0x1032 P=0x0 N=0x0 B=0x1022 Text="Utilities"[0x240]] + --L[#0 T=M VId=0x1033 Text="Copy Flight Mode Settings"[0x23D] MId=0x1032 ] + --L[#1 T=LM_nc VId=0x1001 Text="Enabled F-Modes"[0x88] Val=2 NL=(0->9,2,S=182) [182->191,184] MId=0x1032 ] + + ctx.Menu = { MenuId = 0x1032, TextId = 0x240, PrevId = 0, NextId = 0, BackId = 0x1022 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x23D, ValId = 0x1033 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x88, ValId = 0x1001, Min=182, Max=191, Def=184, Val=2 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x1033) then + --M[Id=0x1033 P=0x0 N=0x0 B=0x1032 Text="Copy Flight Mode Settings"[0x23D]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=0 [0->10,0] MId=0x1033 ] + --L[#1 T=M VId=0x1033 Text="WARNING: "Target""[0x260] MId=0x1033 ] + --L[#2 T=M VId=0x1033 Text="flight mode will be overwritten"[0x261] MId=0x1033 ] + --L[#3 T=M VId=0x1033 Text="by "Source""[0x262] MId=0x1033 ] + --L[#4 T=LM_nc VId=0x1004 Text="Source Flight Mode"[0x23E] Val=0|"FM1" NL=(0->9,0,S=182) [182->191,182] MId=0x1033 ] + --L[#5 T=LM_nc VId=0x1005 Text="Target Flight Mode"[0x23F] Val=0|"FM1" NL=(0->9,0,S=182) [182->191,182] MId=0x1033 ] + --L[#6 T=M VId=0x1035 Text="Apply"[0x90] MId=0x1034 ] + + + ctx.Menu = { MenuId = 0x1033, TextId = 0x23D, PrevId = 0, NextId = 0, BackId = 0x1032 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x260, ValId = 0x1033 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x261, ValId = 0x1033 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x262, ValId = 0x1033 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x23E, ValId = 0x1004, Min=182, Max=191, Def=182, Val=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x23F, ValId = 0x1005, Min=182, Max=191, Def=182, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1034 } + + ctx.SelLine = 4 + lastGoodMenu = menuId + elseif (menuId==0x1034) then + --M[Id=0x1033 P=0x0 N=0x0 B=0x1032 Text="Copy Flight Mode Settings"[0x23D]] + + --L[#1 T=M VId=0x1033 Text="Are you sure you want to ovewrite the \"Target\""[0x251] MId=0x1033 ] + --L[#2 T=M VId=0x1033 Text="with the \"Source\" ? "[0x252] MId=0x1033 ] + --L[#3 T=M VId=0x1033 Text=""[0x253] MId=0x1033 ] + --L[#4 T=LM_nc VId=0x1004 Text="Source Flight Mode"[0x23E] Val=0|"FM1" NL=(0->0,0,S=182) [182->182,182] MId=0x1033 ] + --L[#5 T=LM_nc VId=0x1005 Text="Target Flight Mode"[0x23F] Val=1|"FM2" NL=(0->0,0,S=182) [182->182,182] MId=0x1033 ] + --L[#6 T=M VId=0x1035 Text="YES"[0x259] MId=0x1034 ] + + + ctx.Menu = { MenuId = 0x1034, TextId = 0x23D, PrevId = 0x1033, NextId = 0, BackId = 0x1033 } + + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x251, ValId = 0x1034 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x252, ValId = 0x1034 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x253, ValId = 0x1034 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x23E, ValId = 0x1004, Min=182, Max=182, Def=182, Val=0 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x23F, ValId = 0x1005, Min=182, Max=182, Def=182, Val=1 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x259, ValId = 0x1035 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1035) then + --M[Id=0x1035 P=0x0 N=0x0 B=0x1032 Text="Copy Flight Mode Settings"[0x23D]] + --L[#3 T=M VId=0x1032 Text="Complete"[0x93] MId=0x1035 ] + + ctx.Menu = { MenuId = 0x1035, TextId = 0x23D, PrevId = 0, NextId = 0, BackId = 0x1032 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1032 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x102A) then + --M[Id=0x102A P=0x0 N=0x0 B=0x1022 Text="SAFE/Panic Mode Setup"[0xCA]] + --L[#2 T=M VId=0x102B Text="Panic"[0x8B] MId=0x102A ] + --L[#3 T=M VId=0x102D Text="Throttle to Pitch"[0x1EE] MId=0x102A ] + --L[#4 T=M VId=0x1030 Text="Attitude Trim"[0x1E6] MId=0x102A ] + --L[#5 T=LM_nc VId=0x1006 Text="SAFE Failsafe FMode"[0x1FD] Val=0|"FM1" NL=(0->10,0,S=181) [181->191,181] MId=0x102A ] + --L[#6 T=M VId=0x1031 Text="Failsafe Angles"[0x1F6] MId=0x102A ] + + ctx.Menu = { MenuId = 0x102A, TextId = 0xCA, PrevId = 0, NextId = 0, BackId = 0x1022 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x8B, ValId = 0x102B } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x1EE, ValId = 0x102D } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x1E6, ValId = 0x1030 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x1FD, ValId = 0x1006, Min=182, Max=191, Def=182, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x1F6, ValId = 0x1031 } + + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x102B) then + --M[Id=0x102B P=0x0 N=0x0 B=0x102A Text="Panic"[0x8B]] + --L[#0 T=LM VId=0x1000 Text="Panic Channel"[0xD2] Val=0|"Inhibit?" NL=(0->32,0,S=53) [53->85,53] MId=0x102B ] + --L[#1 T=LM VId=0x1001 Text="Panic Delay"[0x8E] Val=0|"Inh" NL=(0->1,0,S=3) [3->4,3] MId=0x102B ] + --L[#2 T=LM VId=0x1002 Text="Panic Flight Mode"[0x1FC] Val=0|"FM1" NL=(0->10,0,S=181) [181->191,181] MId=0x102B ] + --L[#3 T=V_nc VId=0x1003 Text="Roll Right"[0x1E9] Val=30 [0->90,30] MId=0x102B ] + --L[#4 T=V_nc VId=0x1004 Text="Roll Left"[0x1EA] Val=30 [0->90,30] MId=0x102B ] + --L[#5 T=V_nc VId=0x1005 Text="Pitch Down"[0x1EB] Val=30 [0->75,30] MId=0x102B ] + --L[#6 T=V_nc VId=0x1006 Text="Pitch Up"[0x1EC] Val=30 [0->75,30] MId=0x102B ] + + ctx.Menu = { MenuId = 0x102B, TextId = 0x8B, PrevId = 0, NextId = 0, BackId = 0x102A } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU, TextId = 0xD2, ValId = 0x1000, Min=53, Max=85, Def=53, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x8E, ValId = 0x1001, Min=3, Max=4, Def=3, Val=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1FC, ValId = 0x1002, Min=181, Max=191, Def=181, Val=0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1E9, ValId = 0x1003, Min=0, Max=90, Def=30, Val=30 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EA, ValId = 0x1004, Min=0, Max=90, Def=30, Val=30 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1E9, ValId = 0x1005, Min=0, Max=75, Def=30, Val=30 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EC, ValId = 0x1006, Min=0, Max=75, Def=30, Val=30 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x102D) then + --M[Id=0x102D P=0x0 N=0x0 B=0x102A Text="SAFE - Throttle to Pitch"[0x269]] + --L[#0 T=M VId=0x102D Text="Postive = Up, Negative = Down"[0x254] MId=0x102D ] + --L[#1 T=M VId=0x102D Text="Low Thr to Pitch"[0x1EF] MId=0x102D ] + --L[#2 T=V_nc VId=0x1001 Text="Threshold"[0x1F3] Val=30 [0->50,30] MId=0x102D ] + --L[#3 T=V_de VId=0x1002 Text="Angle"[0x1F4] Val=0 [-45->45,0] MId=0x102D ] + --L[#4 T=M VId=0x102D Text="High Thr to Pitch"[0x1F0] MId=0x102D ] + --L[#5 T=V_nc VId=0x1005 Text="Threshold"[0x1F3] Val=70 [51->100,70] MId=0x102D ] + --L[#6 T=V_de VId=0x1006 Text="Angle"[0x1F4] Val=0 [-45->45,0] MId=0x102D ] + + ctx.Menu = { MenuId = 0x102D, TextId = 0x269, PrevId = 0, NextId = 0, BackId = 0x102A } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x254, ValId = 0x102D } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x1EF, ValId = 0x102D } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1F3, ValId = 0x1001, Min=0, Max=50, Def=30, Val=30 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x1F4, ValId = 0x1002, Min=-45, Max=45, Def=0, Val=0 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x1F0, ValId = 0x102D } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1F3, ValId = 0x1005, Min=51, Max=100, Def=70, Val=70 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x1F4, ValId = 0x1006, Min=-45, Max=45, Def=0, Val=0 } + + ctx.SelLine = 2 + lastGoodMenu = menuId + elseif (menuId==0x104F) then + --M[Id=0x104F P=0x0 N=0x1050 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x104F Text="Make sure the model has been" MId=0x104F ] + --L[#1 T=M VId=0x104F Text="configured, including wing type," MId=0x104F ] + --L[#2 T=M VId=0x104F Text="reversing, travel, trimmed, etc." MId=0x104F ] + --L[#3 T=M VId=0x104F [0->0,2] Text="before continuing setup." MId=0x104F ] + --L[#4 T=M VId=0x104F [0->0,2] Text="" MId=0x104F ] + --L[#5 T=M VId=0x104F [0->0,2] Text="" MId=0x104F ] + + ctx.Menu = { MenuId = 0x104F, TextId = 0x00F9, PrevId = 0, NextId = 0x1050, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x0100, ValId = 0x104F } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x0101, ValId = 0x104F } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0102, ValId = 0x104F } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0103, ValId = 0x104F } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0104, ValId = 0x104F } + ctx.SelLine = menuLib.NEXT_BUTTON + lastGoodMenu = menuId + elseif (menuId==0x1050) then + + --M[Id=0x1050 P=0x104F N=0x1051 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x1050 Text="Any wing type, channel assignment," MId=0x1050 ] + --L[#1 T=M VId=0x1050 Text="subtrim, or servo reversing changes" MId=0x1050 + --L[#2 T=M VId=0x1050 Text="require running through initial" MId=0x1050 ] + --L[#3 T=M VId=0x1050 Text="setup again." MId=0x1050 ] + + ctx.Menu = { MenuId = 0x1050, TextId = 0x00F9, PrevId = 0x104F, NextId = 0x1051, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x0106, ValId = 0x1050 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x0107, ValId = 0x1050 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x0108, ValId = 0x1050 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0109, ValId = 0x1050 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x010A, ValId = 0x1050 } + ctx.SelLine = menuLib.NEXT_BUTTON + lastGoodMenu = menuId + elseif (menuId==0x1051) then + --M[Id=0x1051 P=0x0 N=0x0 B=0x1010 Text="First Time Setup"] + --L[#0 T=M VId=0x1051 Text="Set the model level," MId=0x1051 ] + --L[#1 T=M VId=0x1051 Text="and press Continue." MId=0x1051 ] + --L[#2 T=M VId=0x1051 Text="" MId=0x1051 ] + --L[#5 T=M VId=0x1052 Text="Continue" MId=0x1051 ] + --L[#6 T=M VId=0x1053 Text="Set Orientation Manually" MId=0x1051 ] + + ctx.Menu = { MenuId = 0x1051, TextId = 0x00F9, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x021A, ValId = 0x1051 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x021B, ValId = 0x1051 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x021C, ValId = 0x1051 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x0224, ValId = 0x1052 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x0229, ValId = 0x1053 } + + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1052) then + --M[Id=0x1052 P=0x1051 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#0 T=M VId=0x1052 Text="Set the model on its nose,"[0x21F] MId=0x1052 ] + --L[#1 T=M VId=0x1052 Text="and press Continue. If the"[0x220] MId=0x1052 ] + --L[#2 T=M VId=0x1052 Text="orientation on the next"[0x221] MId=0x1052 ] + --L[#3 T=M VId=0x1052 Text="screen is wrong go back"[0x222] MId=0x1052 ] + --L[#4 T=M VId=0x1052 Text="and try again."[0x223] MId=0x1052 ] + --L[#6 T=M VId=0x1053 Text="Continue"[0x224] MId=0x1052 ] + + ctx.Menu = { MenuId = 0x1052, TextId = 0x00A5, PrevId = 0x1051, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x21F, ValId = 0x1052 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x220, ValId = 0x1052 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x221, ValId = 0x1052 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x222, ValId = 0x1052 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x223, ValId = 0x1052 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1053 } + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1053) then + --M[Id=0x1053 P=0x1051 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#5 T=LM_nc VId=0x1000 Text="Orientation"[0x80] MId=0x1053 val=0 (0->23,0,S=203) [203->226,203] ] + --L[#6 T=M VId=0x1054 Text="Continue"[0x224] MId=0x1053 ] + + ctx.Menu = { MenuId = 0x1053, TextId = 0x00A5, PrevId = 0x1051, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x80, ValId = 0x1000, Min=203, Max=226, Def=203, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1054 } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1054) then + --M[Id=0x1054 P=0x1053 N=0x0 B=0x1010 Text="First Time Setup"[0xA5]] + --L[#1 T=M VId=0x7CA5 Text="Gain Channel Select"[0xAD] ] + --L[#6 T=M VId=0x1 Text="Apply"[0x90] MId=0x1054 ] + + ctx.Menu = { MenuId = 0x1054, TextId = 0x00A5, PrevId = 0x1053, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xAD, ValId = 0x7CA5 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x01 } -- Special save&reboot?? + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1055) then + --M[Id=0x1055 P=0x0 N=0x0 B=0x1010 Text="First Time SAFE Setup"[0x20D]] + --L[#0 T=M VId=0x1055 Text="Before setting up SAFE"[0x255] MId=0x1055 ] + --L[#1 T=M VId=0x1055 Text="a Fligt Mode channel"[0x256] MId=0x1055 ] + --L[#2 T=M VId=0x1055 Text="most be configured."[0x257] MId=0x1055 ] + --L[#5 T=M VId=0x7CA7 Text="FM Channel"[0x78] MId=0x1055 ] + --L[#6 T=M VId=0x1056 Text="Continue"[0x224] MId=0x1055 ] + + ctx.Menu = { MenuId = 0x1055, TextId = 0x20D, PrevId = 0x1053, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x255, ValId = 0x1055 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x256, ValId = 0x1055 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x257, ValId = 0x1055 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x78, ValId = 0x7CA7 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x224, ValId = 0x1056 } + ctx.SelLine = 5 + lastGoodMenu = menuId + elseif (menuId==0x1056) then + --M[Id=0x1056 P=0x1055 N=0x1057 B=0x1010 Text="First Time SAFE Setup"[0x20D]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=1 [0->10,0] MId=0x1056 ] + --L[#1 T=M VId=0x1056 Text="Select the desired flight mode"[0x25A] MId=0x1056 ] + --L[#2 T=M VId=0x1056 Text="switch position to adjust settings"[0x25B] MId=0x1056 ] + --L[#3 T=M VId=0x1056 Text="for each flight mode"[0x25C] MId=0x1056 ] + --L[#4 T=M VId=0x1056 Text=""[0x25D] MId=0x1056 ] + --L[#5 T=M VId=0x1056 Text=""[0x25E] MId=0x1056 ] + + ctx.Menu = { MenuId = 0x1056, TextId = 0x20D, PrevId = 0x1053, NextId = 0x1057, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x25A, ValId = 0x1056 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x25B, ValId = 0x1056 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x25C, ValId = 0x1056 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x25D, ValId = 0x1056 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x25E, ValId = 0x1056 } + + ctx.SelLine = 7 + lastGoodMenu = menuId + elseif (menuId==0x1057) then + --M[Id=0x1057 P=0x1056 N=0x1059 B=0x1010 Text="First Time SAFE Setup"[0x20D]] + --L[#0 T=M VId=0x1057 Text="AS3X gains must be tuned"[0x20E] MId=0x1057 ] + --L[#1 T=M VId=0x1057 Text="and active i SAFE Flight Modes"[0x20F] MId=0x1057 ] + --L[#2 T=M VId=0x1057 Text="to help reduce wobble."[0x210] MId=0x1057 ] + --L[#3 T=M VId=0x1057 Text=""[0x211] MId=0x1057 ] + --L[#4 T=M VId=0x1057 Text=""[0x212] MId=0x1057 ] + --L[#5 T=M VId=0x1057 Text=""[0x213] MId=0x1057 ] + + ctx.Menu = { MenuId = 0x1057, TextId = 0x20D, PrevId = 0x1056, NextId = 0x1059, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x20E, ValId = 0x1057 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x20F, ValId = 0x1057 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x210, ValId = 0x1057 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x211, ValId = 0x1057 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x212, ValId = 0x1057 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x213, ValId = 0x1057 } + + ctx.SelLine = 7 + lastGoodMenu = menuId + + elseif (menuId==0x1059) then + --M[Id=0x1059 P=0x1057 N=0x105A B=0x1010 Text="First Time SAFE Setup"[0x20D]] + --L[#0 T=M VId=0x1059 Text="Leven model and capture attiude"[0xCD] MId=0x1059 ] + --L[#1 T=M VId=0x1059 Text="Attitude Trim"[0x1E6] MId=0x1059 ] + --L[#2 T=V_de VId=0x1002 Text="Roll"[0x40] Val=13 [-45->45,0] MId=0x1059 ] + --L[#3 T=V_de VId=0x1003 Text="Pitch"[0x41] Val=5 [-45->45,0] MId=0x1059 ] + --L[#5 T=M VId=0x1059 Text="Positive = Nose Up/Roll Right"[0x267] MId=0x1059 ] + --L[#6 T=M VId=0x1059 Text="Negative = Nose Down/Roll Left"[0x268] MId=0x1059 ] + + ctx.Menu = { MenuId = 0x1059, TextId = 0x20D, PrevId = 0x1057, NextId = 0x105A, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xCD, ValId = 0x1059 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x1E6, ValId = 0x1059 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x40, ValId = 0x1002, Min=-45, Max=45, Def=0, Val=13 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_DEGREES, TextId = 0x41, ValId = 0x1003, Min=-45, Max=45, Def=0, Val=5 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x267, ValId = 0x1059 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x268, ValId = 0x1059 } + + ctx.SelLine = 7 + lastGoodMenu = menuId + elseif (menuId==0x105A) then + --M[Id=0x105A P=0x1059 N=0x105B B=0x1010 Text="First Time SAFE Setup"[0x20D]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode"[0x8001] Val=0 [0->10,0] MId=0x105A ] + --L[#1 T=LM VId=0x1001 Text="Safe Mode"[0x1F8] Val=3|"Inh" NL=(0->244,3,S=0) [0->244,3] MId=0x105A ] + --L[#2 T=M VId=0x105A Text="Angle Limits "[0x226] MId=0x105A ] + --L[#3 T=V_nc VId=0x1003 Text="Roll Right"[0x1E9] Val=60 [10->90,60] MId=0x105A ] + --L[#4 T=V_nc VId=0x1004 Text="Roll Left"[0x1EA] Val=60 [10->90,60] MId=0x105A ] + --L[#5 T=V_nc VId=0x1005 Text="Pitch Down"[0x1EB] Val=40 [10->75,40] MId=0x105A ] + --L[#6 T=V_nc VId=0x1006 Text="Pitch Up"[0x1EC] Val=50 [10->75,50] MId=0x105A ] + + ctx.Menu = { MenuId = 0x105A, TextId = 0x1DE, PrevId = 0x1059, NextId = 0x105B, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1F8, ValId = 0x1001, Min=0, Max=244, Def=3, Val=3 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x226, ValId = 0x105A } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1E9, ValId = 0x1003, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EA, ValId = 0x1004, Min=10, Max=90, Def=60, Val=60 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EB, ValId = 0x1004, Min=10, Max=75, Def=40, Val=40 } + ctx.MenuLines[6] = { lineNum = 7, Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x1EC, ValId = 0x1004, Min=10, Max=75, Def=50, Val=50 } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x105B) then + --M[Id=0x105B P=0x105A N=0x0 B=0x1000 Text="First Time SAFE Setup"[0x20D]] + --L[#3 T=M VId=0x1 Text="Apply"[0x90] MId=0x1064 ] + + ctx.Menu = { MenuId = 0x105B, TextId = 0x20D, PrevId = 0x105A, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1 } -- reset RX + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x105C) then + -- M[Id=0x105C P=0x0 N=0x0 B=0x1010 Text="SAFE Select"[0x1F9]] + --L[#0 T=V_nc VId=0x1000 Text="Flight Mode 1"[0x8001] val=1 [0->10,0] MId=0x105C ] + --L[#1 T=LM VId=0x1001 Text="SAFE Select Channel"[0x1D7] val=5 NL=(0->32,53,S=53) [53->85,53] MId=0x105C] + --L[#2 T=LM VId=0x1002 Text="AS3X"[0x1DC] val=1 NL=(0->1,1,S=1) [1->2,1] MId=0x105C] + --L[#3 T=LM VId=0x1003 Text="SAFE"[0xDA] val=0 NL=(0->0,0,S=1) [1->1,1] MId=0x105C ] + --L[#6 T=LM VId=0x1006 Text="SAFE Select"[0x1F9] val=0 NL=(0->1,1,S=1) [1->2,1] MId=0x105C ] + + ctx.Menu = { MenuId = 0x105C, TextId = 0x01F9, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8001, ValId = 0x1000, Min=0, Max=10, Def=0, Val=1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1D7, ValId = 0x1001, Min=53, Max=85, Def=53, Val=5 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1DC, ValId = 0x1002, Min=1, Max=2, Def=1, Val=1 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU, TextId = 0xDA, ValId = 0x1003, Min=1, Max=1, Def=1, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x1F9, ValId = 0x1004, Min=1, Max=2, Def=1, Val=0 } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x105E) then + -- M[Id=0x105E P=0x0 N=0x0 B=0x1000 Text="Other settings"] + -- L[#1 T=M VId=0x1060 Text="Failsafe" MId=0x105E ] + -- L[#2 T=M VId=0x1064 Text="Enter Receiver Bind Mode" MId=0x105E ] + -- L[#3 T=M VId=0x1065 Text="Frame Rate" MId=0x105E ] + -- L[#4 T=M VId=0x1067 Text="Factory Reset" MId=0x105E ] + -- L[#5 T=M VId=0x1069 Text="Restore from Backup" MId=0x105E ] + -- L[#6 T=M VId=0x106A Text="Save to Backup" MId=0x105E ] + + ctx.Menu = { MenuId = 0x105E, TextId = 0x0227, PrevId = 0, NextId = 0, BackId = 0x1010 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x004A, ValId = 0x1060 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x019C, ValId = 0x1064 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x0085, ValId = 0x1065 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x0097, ValId = 0x1067 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x020A, ValId = 0x1069 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x0209, ValId = 0x106A } + + ctx.SelLine = 1 + lastGoodMenu = menuId + elseif (menuId==0x1060) then + --M[Id=0x1060 P=0x0 N=0x0 B=0x105E Text="Failsafe"] + --L[#0 T=M VId=0x1061 Text="Failsafe" MId=0x1060 ] + --L[#1 T=M VId=0x1062 Text="Capture Failsafe Positions" MId=0x1060 ] + + ctx.Menu = { MenuId = 0x1060, TextId = 0x004A, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x004A, ValId = 0x1061 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x009A, ValId = 0x1062 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1061) then + --M[Id=0x1061 P=0x0 N=0x0 B=0x1060 Text="Failsafe"] + --L[#0 T=LM_nc VId=0x1000 Text="Outputs:" val=0 NL=(0->19,54,S=54) [54->73,54] MId=0x1061 ] + --L[#2 T=LM_tog VId=0x1002 Text="Custom Failsafe:" val=0 NL=(0->1,95,S=95) [95->96,95] MId=0x1061 ] + --L[#3 T=V_% VId=0x1003 Text="Position:" val=-100 [-150->150,0] MId=0x1061 ] + + ctx.Menu = { MenuId = 0x1061, TextId = 0x004A, PrevId = 0, NextId = 0, BackId = 0x1060 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x0050, ValId = 0x1000, Min=54, Max=73, Def=54, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x009C, ValId = 0x1002, Min=95, Max=96, Def=95, Val=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x004E, ValId = 0x1002, Min=-150, Max=150, Def=0, Val=-100 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1064) then + --M[Id=0x1064 P=0x0 N=0x0 B=0x105E Text="Enter Receiver Bind Mode"[0x19C]] + --L[#3 T=M VId=0x1 Text="Apply"[0x90] MId=0x1064 ] + + ctx.Menu = { MenuId = 0x1064, TextId = 0x19C, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1 } -- reset RX + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1065) then + --M[Id=0x1065 P=0x0 N=0x0 B=0x105E Text="Frame Rate"] + --L[#0 T=LM VId=0x1000 Text="Output Channel 1:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#1 T=LM VId=0x1001 Text="Output Channel 2:" val=47 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#2 T=LM VId=0x1002 Text="Output Channel 3:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#3 T=LM VId=0x1003 Text="Output Channel 4:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#4 T=LM VId=0x1004 Text="Output Channel 5:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + --L[#5 T=LM VId=0x1005 Text="Output Channel 6:" val=46 NL=(0->244,46|S=0) [0->244,0] MId=0x1065 ] + + ctx.Menu = { MenuId = 0x1065, TextId = 0x0085, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0051, ValId = 0x1000, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0052, ValId = 0x1001, Min=0, Max=244, Def=46, Val=47 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0053, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0054, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0055, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x0056, ValId = 0x1002, Min=0, Max=244, Def=46, Val=46 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1067) then + --M[Id=0x1067 P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x1067 Text="This will reset the"[0x22C] MId=0x1067 ] + --L[#1 T=M VId=0x1067 Text="configuration to factory"[0x22D] MId=0x1067 ] + --L[#2 T=M VId=0x1067 Text="defaults. This does not"[0x22E] MId=0x1067 ] + --L[#3 T=M VId=0x1067 Text="affect the backup config."[0x22F] MId=0x1067 ] + --L[#4 T=M VId=0x1067 Text=""[0x230] MId=0x1067 ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x1067 ] + + ctx.Menu = { MenuId = 0x1067, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x22C, ValId = 0x1067 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x22D, ValId = 0x1067 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x22E, ValId = 0x1067 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x22F, ValId = 0x1067 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x230, ValId = 0x1067 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1068) then + --M[Id=0x1068 P=0x0 N=0x0 B=0x1000 Text="Done"[0x94]] + --L[#3 T=M VId=0x1000 Text="Complete"[0x93] MId=0x1068 ] + + ctx.Menu = { MenuId = 0x1068, TextId = 0x94, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1000 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1069) then + --M[Id=0x1069 P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x1069 Text="This will overwrite the"[0x236] MId=0x1069 ] + --L[#1 T=M VId=0x1069 Text="current config with"[0x237] MId=0x1069 ] + --L[#2 T=M VId=0x1069 Text="that which is in"[0x238] MId=0x1069 ] + --L[#3 T=M VId=0x1069 Text="the backup memory."[0x239] MId=0x1069 ] + --L[#4 T=M VId=0x1069 Text=""[0x23A] MId=0x1069 ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x1069 ] + + ctx.Menu = { MenuId = 0x1069, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x236, ValId = 0x1069 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x237, ValId = 0x1069 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x238, ValId = 0x1069 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x239, ValId = 0x1069 } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x23A, ValId = 0x1069 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x106A) then + --M[Id=0x106A P=0x0 N=0x0 B=0x105E Text="WARNING!"[0x22B]] + --L[#0 T=M VId=0x106A Text="This will overwrite the"[0x231] MId=0x106A ] + --L[#1 T=M VId=0x106A Text="backup memory with your"[0x232] MId=0x106A ] + --L[#2 T=M VId=0x106A Text="current configuartion."[0x233] MId=0x106A ] + --L[#3 T=M VId=0x106A Text=""[0x234] MId=0x106A ] + --L[#4 T=M VId=0x106A Text=""[0x235] MId=0x106A ] + --L[#6 T=M VId=0x1068 Text="Apply"[0x90] MId=0x106A ] + + ctx.Menu = { MenuId = 0x106A, TextId = 0x22B, PrevId = 0, NextId = 0, BackId = 0x105E } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x231, ValId = 0x106A } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x232, ValId = 0x106A } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x233, ValId = 0x106A } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x234, ValId = 0x106A } + ctx.MenuLines[4] = { Type = LINE_TYPE.MENU, TextId = 0x235, ValId = 0x106A } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x1068 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x7CA5) then + --M[Id=0x7CA5 P=0x0 N=0x1021 B=0x1021 Text="Gain Channel Select"[0xAD]] + --L[#0 T=LM VId=0x1000 Text="Gain Channel"[0x89] val=7 N=(0->32,53,S=53) [53->85,53] MId=0x7CA5 ] + + ctx.Menu = { MenuId = 0x7CA5, TextId = 0xAD, PrevId = 0, NextId = 0x1054, BackId = 0x1054 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x89, ValId = 0x1000, Min=53, Max=85, Def=53, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x7CA6) then + --M[Id=0x7CA6 P=0x0 N=0x1021 B=0x1021 Text="FM Channel"[0x78]] + --L[#0 T=LM VId=0x1000 Text="FM Channel"[0x78] val=7 N=(0->32,53,S=53) [53->85,53] MId=0x7CA6 ] + + ctx.Menu = { MenuId = 0x7CA6, TextId = 0x78, PrevId = 0, NextId = 0x1021, BackId = 0x1021 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x78, ValId = 0x1000, Min=53, Max=85, Def=53, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x7CA7) then + --M[Id=0x7CA7 P=0x0 N=0x1055 B=0x1055 Text="FM Channel"[0x78]] + --L[#0 T=LM VId=0x1000 Text="FM Channel"[0x78] val=7 N=(0->32,53,S=53) [53->85,53] MId=0x7CA6 ] + + ctx.Menu = { MenuId = 0x7CA7, TextId = 0x78, PrevId = 0, NextId = 0x1055, BackId = 0x1055 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU, TextId = 0x78, ValId = 0x1000, Min=53, Max=85, Def=53, Val=0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x0001) then + -- Save Settings and Reboot + ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.SelLine = menuLib.BACK_BUTTON + + else + print("NOT IMPLEMENTED") + ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = menuLib.BACK_BUTTON + end + + menuLib.PostProcessMenu() +end + +local function FC6250HX_loadMenu(menuId) + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context + + if (menuId==0x1000) then + --M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"[0x4B]] + --L[#0 T=M VId=0x1100 Text="Swashplate"[0xD3] MId=0x1000 ] + --L[#1 T=M VId=0x1200 [0->0,2] Text="Tail rotor"[0xDD] MId=0x1000 ] + + --L[#2 T=M VId=0x1280 Text="Governor"[0xF2] + + --L[#3 T=M VId=0x1400 [0->0,2] Text="SAFE"[0xDA] MId=0x1000 ] + --L[#5 T=M VId=0x1300 [0->0,2] Text="Setup"[0xDE] MId=0x1000 ] + --L[#6 T=M VId=0x1700 [0->0,2] Text="System Setup"[0x86] MId=0x1000 ] + + ctx.Menu = { MenuId = 0x1000, TextId = 0x004B, PrevId = 0, NextId = 0, BackId = 0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1100 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1200 } + + if (not RX_Initialized) then + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x1280 } + end + + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xDA, ValId = 0x1400 } + + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0xDE, ValId = 0x1300 } + ctx.MenuLines[6] = { Type = LINE_TYPE.MENU, TextId = 0x86, ValId = 0x1700 } + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1100) then + --M[Id=0x1100 P=0x0 N=0x0 B=0x1000 Text="Swashplate"[0xD3]] + --L[#0 T=M VId=0x1110 val=nil [0->0,2] Text="Roll"[0x40] MId=0x1100 ] + --L[#1 T=M VId=0x1120 val=nil [0->0,2] Text="Pitch"[0x41] MId=0x1100 ] + --L[#2 T=V_i8 VId=0x1103 Text="Agility"[0xD5] val=100 [0->200,100] MId=0x1100 ] + + ctx.Menu = { MenuId = 0x1100, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x40, ValId = 0x1110, Min=0, Max=0, Def=3, Val=nil } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x41, ValId = 0x1120, Min=0, Max=0, Def=2, Val=nil } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD5, ValId = 0x1103, Min=0, Max=200, Def=100, Val=100 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1110) then + --M[Id=0x1110 P=0x0 N=0x0 B=0x1100 Text="Roll"[0x40]] + --L[#0 T=V_i16 VId=0x1111 Text="@ per sec"[0xDC] val=270 [0->900,270] MId=0x1110 ] + --L[#1 T=V_nc VId=0x1112 Text="FLIGHT MODE"[0x8000] val=1 [0->5,0] MId=0x1110 ] + --L[#2 T=V_i8 VId=0x1113 Text="Proportional"[0x71] val=100 [0->255,100] MId=0x1110 ] + --L[#3 T=V_i8 VId=0x1114 Text="Integral"[0x72] val=100 [0->255,100] MId=0x1110 ] + --L[#4 T=V_i8 VId=0x1115 Text="Derivate"[0x73] val=7 [0->255,7] MId=0x1110 ] + + ctx.Menu = { MenuId = 0x1110, TextId = 0x40, PrevId = 0, NextId = 0, BackId = 0x1100 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1111, Min=0, Max=900, Def=270, Val=270 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1112, Min=0, Max=5, Def=0, Val=1 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1113, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1114, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1115, Min=0, Max=255, Def=7, Val=7 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1120) then + --M[Id=0x1120 P=0x0 N=0x0 B=0x1100 Text="Pitch"[0x41]] + --L[#0 T=V_i16 VId=0x1121 Text="@ per sec"[0xDC] Val=270 [0->900,270] MId=0x1120 ] + --L[#1 T=V_i8 VId=0x1212 Text="Start"[0x92] Val=nil [5->200,25] MId=0x1200 ] + --L[#2 T=V_i8 VId=0x1213 Text="Stop"[0xD8] Val=nil [5->200,25] MId=0x1200 ] + --L[#3 T=V_nc VId=0x1122 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1120 ] + --L[#4 T=V_i8 VId=0x1123 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1120 ] + --L[#5 T=V_i8 VId=0x1124 Text="Integral"[0x72] Val=100 [0->255,100] MId=0x1120 ] + --L[#6 T=V_i8 VId=0x1125 Text="Derivate"[0x73] Val=14 [0->255,14] MId=0x1120 ] + + ctx.Menu = { MenuId = 0x1120, TextId = 0x41, PrevId = 0, NextId = 0, BackId = 0x1100 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1121, Min=0, Max=900, Def=270, Val=270 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1123, Min=5, Max=200, Def=25, Val=25 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1123, Min=5, Max=200, Def=26, Val=100 } + + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1122, Min=0, Max=5, Def=0, Val=1 } + + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1123, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1124, Min=0, Max=255, Def=95, Val=95 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1125, Min=0, Max=255, Def=45, Val=45 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1200) then + --M[Id=0x1200 P=0x0 N=0x0 B=0x1000 Text="Tail rotor"[0xDD]] + --L[#0 T=V_i16 VId=0x1211 Text="@ per sec"[0xDC] Val=550 [0->1280,550] MId=0x1200 ] + --L[#1 T=V_i8 VId=0x1212 Text="Start"[0x92] Val=25 [5->200,25] MId=0x1200 ] + --L[#2 T=V_i8 VId=0x1213 Text="Stop"[0xD8] Val=25 [5->200,25] MId=0x1200 ] + --L[#3 T=V_nc VId=0x1214 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1200 ] + --L[#4 T=V_i8 VId=0x1215 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1200 ] + --L[#5 T=V_i8 VId=0x1216 Text="Integral"[0x72] Val=95 [0->255,95] MId=0x1200 ] + --L[#6 T=V_i8 VId=0x1217 Text="Derivate"[0x73] Val=45 [0->255,45] MId=0x1200 ] + + ctx.Menu = { MenuId = 0x1200, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I16, TextId = 0xDC, ValId = 0x1211, Min=0, Max=1280, Def=550, Val=550 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1212, Min=5, Max=200, Def=25, Val=25 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1213, Min=5, Max=200, Def=26, Val=100 } + + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1214, Min=0, Max=5, Def=0, Val=1 } + + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1215, Min=0, Max=255, Def=100, Val=100 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x72, ValId = 0x1216, Min=0, Max=255, Def=95, Val=95 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x73, ValId = 0x1217, Min=0, Max=255, Def=45, Val=45 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1280) then -- TODO + --M[Id=0x1200 P=0x0 N=0x0 B=0x1000 Text="Governor"[0xF0]] + --L[#4 T=V_i8 VId=0x1215 Text="Proportional"[0x71] Val=100 [0->255,100] MId=0x1200 ] + --L[#5 T=V_i8 VId=0x1216 Text="Integral"[0x72] Val=95 [0->255,95] MId=0x1200 ] + --L[#3 T=V_nc VId=0x1214 Text=" FLIGHT MODE"[0x8000] Val=1 [0->5,0] MId=0x1200 ] + --L[#6 T=V_i8 VId=0x1217 Text="Head Speed"[0x26B] Val=45 [0->255,45] MId=0x1200 ] + + ctx.Menu = { MenuId = 0x1280, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x92, ValId = 0x1212, Min=5, Max=200, Def=25, Val=25 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xD8, ValId = 0x1213, Min=5, Max=200, Def=26, Val=100 } + + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1214, Min=0, Max=5, Def=0, Val=1 } + + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x71, ValId = 0x1215, Min=0, Max=255, Def=100, Val=100 } + + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1300) then + --M[Id=0x1300 P=0x0 N=0x0 B=0x1000 Text="Setup"[0xDE]] + --L[#0 T=M VId=0x1310 Text="Swashplate"[0xD3] MId=0x1300 ] + --L[#1 T=M VId=0x1360 Text="Tail rotor"[0xDD] MId=0x1300 ] + + -- L[#2 T=M VId=0x13C0 Text="Throttle"[0x201] MId=0x1300 A=0x0] + -- L[#3 T=M VId=0x13B0 Text="Gyro settings"[0xF9] MId=0x1300 A=0x0] + + --L[#4 T=LM_nc VId=0x1701 Text="FM Channel"[0x78] val=1 NL=(0->8,1,S=12) [12->20,13] MId=0x1300 ] + --L[#5 T=LM_nc VId=0x1702 Text="Gain Channel"[0x89] val=0 NL=(0->8,1,S=12)] [12->20,13] MId=0x1300 ] + --L[#6 T=LM_nc VId=0x1703 Text="Output Channel 6"[0x56] val=1 NL=(0->12,0,S=53) [53->65,53] MId=0x1300 ] + + ctx.Menu = { MenuId = 0x1300, TextId = 0xDE, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xD3, ValId = 0x1310 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDD, ValId = 0x1360 } + + if (not RX_Initialized) then + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x201, ValId = 0x13C0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xF9, ValId = 0x13B0 } + end + + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x78, ValId = 0x1701, Min=12, Max=20, Def=13, Val=1 } + ctx.MenuLines[5] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x89, ValId = 0x1702, Min=12, Max=20, Def=13, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x56, ValId = 0x1702, Min=53, Max=65, Def=53, Val=1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1310) then + --M[Id=0x1310 P=0x0 N=0x0 B=0x1300 Text="Swashplate"[0xD3]] + --L[#0 T=M VId=0x1330 Text="Output Setup"[0x49] MId=0x1310 ] + --L[#1 T=M VId=0x1320 Text="AFR"[0xDF] MId=0x1310 ] + --L[#2 T=V_% VId=0x1311 Text="E-Ring"[0xE4] Val=100 [50->150,100] MId=0x1310 ] + --L[#3 T=V_% VId=0x1312 Text="Phasing"[0xE2] Val=0 [-45->45,0] MId=0x1310 ] + --L[#4 T=V_% VId=0x1313 Text="Decay"[0x208] Val=50 [0->100,50] MId=0x1310 ] + + ctx.Menu = { MenuId = 0x1310, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1300 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x49, ValId = 0x1330 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xDF, ValId = 0x1320 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE4, ValId = 0x1311, Min=50, Max=150, Def=100, Val=100 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE2, ValId = 0x1312, Min=-45, Max=45, Def=0, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x208, ValId = 0x1313, Min=0, Max=100, Def=50, Val=50 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1320) then + --M[Id=0x1320 P=0x0 N=0x0 B=0x1310 Text="AFR"[0xDF]] + --L[#0 T=V_% VId=0x1321 Text="Roll"[0x40] Val=-75 % [-127->127,-75] MId=0x1320 ] + --L[#1 T=V_% VId=0x1322 Text="Pitch"[0x41] Val=-75 % [-127->127,-75] MId=0x1320 ] + --L[#2 T=V_% VId=0x1323 Text="Collective"[0xE0] Val=45 % [5->127,45] MId=0x1320 ] + --L[#3 T=V_% VId=0x1324 Text="Differential"[0x45] Val=0 % [-25->25,0] MId=0x1320 ] + + ctx.Menu = { MenuId = 0x1320, TextId = 0xDF, PrevId = 0, NextId = 0, BackId = 0x1310 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x40, ValId = 0x1321, Min=-127, Max=127, Def=-75, Val=-75 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x41, ValId = 0x1322, Min=-127, Max=127, Def=-75, Val=-75 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE0, ValId = 0x1323, Min=5, Max=127, Def=45, Val=45 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x45, ValId = 0x1324, Min=-25, Max=25, Def=0, Val=0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1330) then + --M[Id=0x1330 P=0x0 N=0x0 B=0x1310 Text="Output Setup"[0x49]] + + ---- Full version + --L[#0 T=LM_nc2 VId=0x1331 Text="Frame Rate"[0x85] Val=nil NL=(0->5,0,S=136) [136->141,136] MId=0x1330 A=0x0] + --L[#1 T=M VId=0x1334 Text="Swash Type"[0xE5] MId=0x1330 A=0x0] + --L[#2 T=M VId=0x1332 Text="Direction"[0xF6] MId=0x1330 A=0x0] + + --L[#3 T=M VId=0x1331 Text="Subtrim"[0xE1] MId=0x1330 ] + + ctx.Menu = { MenuId = 0x1330, TextId = 0x49, PrevId = 0, NextId = 0, BackId = 0x1310 } + + if (not RX_Initialized) then + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0x85, ValId = 0x1331, Min=136, Max=141, Def=136, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0xE5, ValId = 0x1334 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF6, ValId = 0x1332 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 } + ctx.SelLine = 0 + else + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xE1, ValId = 0x1331 } + ctx.SelLine = 0 + end + + lastGoodMenu = menuId + elseif (menuId==0x1331) then + --M[Id=0x1331 P=0x0 N=0x0 B=0x1330 Text="Subtrim"[0xE1]] + --L[#0 T=V_s16 VId=0x1332 Text="Output Channel 1"[0x51] Val=57 [-82->82,0] MId=0x1331 ] + --L[#1 T=V_s16 VId=0x1333 Text="Output Channel 2"[0x52] Val=-17 [-82->82,0] MId=0x1331 ] + --L[#2 T=V_s16 VId=0x1334 Text="Output Channel 3"[0x53] Val=-53 [-82->82,0] MId=0x1331 ] + + ctx.Menu = { MenuId = 0x1331, TextId = 0xE1, PrevId = 0, NextId = 0, BackId = 0x1330 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x51, ValId = 0x1332, Min=-82, Max=82, Def=0, Val=57 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x52, ValId = 0x1333, Min=-82, Max=82, Def=0, Val=-17 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x53, ValId = 0x1334, Min=-82, Max=82, Def=0, Val=-53 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1332) then + --M[Id=0x1332 P=0x0 N=0x0 B=0x1330 Text="Direction"[0xF6]] + --L[#0 T=LM_tog VId=0x1333 Text="Output Channel 1"[0x51] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0] + --L[#1 T=LM_tog VId=0x1334 Text="Output Channel 2"[0x52] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0] + --L[#2 T=LM_tog VId=0x1335 Text="Output Channel 3"[0x53] Val=nil NL=(0->1,0,S=142) [142->143,142] MId=0x1332 A=0x0] + + ctx.Menu = { MenuId = 0x1332, TextId = 0xF6, PrevId = 0, NextId = 0, BackId = 0x1330 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x51, ValId = 0x1333, Min=142, Max=143, Def=142, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x52, ValId = 0x1334, Min=142, Max=143, Def=142, Val=0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x53, ValId = 0x1335, Min=142, Max=143, Def=142, Val=0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1334) then + -- M[Id=0x1334 P=0x0 N=0x0 B=0x1330 Text="Swashplate"[0xD3]] + -- L[#6 T=LM_tog VId=0x1335 Text="Swash Type"[0xE5] Val=nil NL=(0->8,0,S=144) [144->152,144] MId=0x1334 A=0x0] + + ctx.Menu = { MenuId = 0x1334, TextId = 0xD3, PrevId = 0, NextId = 0, BackId = 0x1330 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_NC, TextId = 0xE5, ValId = 0x1335, Min=144, Max=152, Def=144, Val=0 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x1360) then + --M[Id=0x1360 P=0x0 N=0x0 B=0x1300 Text="Tail rotor"[0xDD]] + --L[#0 T=M VId=0x1390 Text="Advanced Setup"[0x99] MId=0x1360 ] + + ctx.Menu = { MenuId = 0x1360, TextId = 0xDD, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x99, ValId = 0x1390 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1390) then + --M[Id=0x1390 P=0x0 N=0x0 B=0x1360 Text="Phasing"[0xE2]] + --L[#0 T=V_% VId=0x1311 Text="Left"[0xE7] Val=0 % [-45->45,0] MId=0x1390 ] + --L[#1 T=V_% VId=0x1312 Text="Right"[0xE8] Val=0 % [-45->45,0] MId=0x1390 ] + + ctx.Menu = { MenuId = 0x1390, TextId = 0xE2, PrevId = 0, NextId = 0, BackId = 0x1360 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE2, ValId = 0x1311, Min=-45, Max=45, Def=0, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0xE8, ValId = 0x1312,Min=-45, Max=45, Def=0, Val=0 } + + + ctx.SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x13B0) then + -- M[Id=0x13B0 P=0x0 N=0x0 B=0x1300 Text="Gyro settings"[0xF9]] + -- L[#0 T=M VId=0x13B1 Text="Orientation"[0x80] MId=0x13B0 A=0x0] + + ctx.Menu = { MenuId = 0x13B0, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x1300 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x80, ValId = 0x13B1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x13B1) then + -- M[Id=0x13B1 P=0x0 N=0x0 B=0x13B5 Text="Gyro settings"[0xF9]] + --L[#6 T=LM_ori VId=0x13B2 Text="Orientation"[0x80] Val=nil NL=(0->7,0,S=203) [203->210,203] MId=0x13B1 A=0x0] + + ctx.Menu = { MenuId = 0x13B1, TextId = 0xF9, PrevId = 0, NextId = 0, BackId = 0x13B5 } + ctx.MenuLines[6] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x80, ValId = 0x13B2, Min=203, Max=210, Def=203, Val=0 } + + ctx.SelLine = 6 + lastGoodMenu = menuId + elseif (menuId==0x13B5) then + --M[Id=0x13B5 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]] + --L[#3 T=M VId=0x13B6 Text="Begin"[0x91] MId=0x13B5 A=0x0] + + ctx.Menu = { MenuId = 0x13B5, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x91, ValId = 0x13B6 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x13B6) then + --M[Id=0x13B6 P=0x0 N=0x0 B=0x13B0 Text="Calibrate Sensor"[0xC7]] + --L[#3 T=M VId=0x13B0 Text="Sensor is Calibrating.. Wait"[0xC8] MId=0x13B6 A=0x0] + + ctx.Menu = { MenuId = 0x13B6, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x13B0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0xC8, ValId = 0x17F1 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x13C0) then + --M[Id=0x13C0 P=0x0 N=0x0 B=0x1300 Text="Throttle"[0x201]] + --L[#0 T=M VId=0x13C1 Text="Failsafe"[0x4A] MId=0x13C0 A=0x0] + --L[#1 T=V_% VId=0x13C2 Text="Hover"[0x204] Val=nil [0->100,65] MId=0x13C0 A=0x10] + --L[#2 T=M VId=0x13D0 Text="Governor"[0xF2] MId=0x13C0 A=0x0] + --L[#4 T=V_nc VId=0x13C3 Text="Flight Mode"[0x8000] Val=nil [0->5,0] MId=0x13C0 A=0x5] + --L[#5 T=V_% VId=0x13C4 Text="Offset"[0x1AA] Val=nil [-25->25,0] MId=0x13C0 A=0x10] + --L[#6 T=V_i8 VId=0x13C5 Text="Soft Start"[0xF4] Val=nil [0->250,0] MId=0x13C0 A=0x0] + + ctx.Menu = { MenuId = 0x13C0, TextId = 0x201, PrevId = 0, NextId = 0, BackId = 0x1300 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0x4A, ValId = 0x13C1 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x204, ValId = 0x13C2, Min=0, Max=100, Def=65, Val=65 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0xF2, ValId = 0x13D0 } + + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x13C3, Min=0, Max=5, Def=0, Val=1 } + ctx.MenuLines[5] = { Type = LINE_TYPE.VALUE_PERCENT, TextId = 0x1AA, ValId = 0x13C4, Min=-25, Max=25, Def=0, Val=0 } + ctx.MenuLines[6] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0xF4, ValId = 0x13C5, Min=0, Max=250, Def=0, Val=1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x13C1) then + --M[Id=0x13C1 P=0x0 N=0x0 B=0x13C0 Text="Failsafe"[0x4A]] + --L[#2 T=M VId=0x13C3 Text="Capture Failsafe Positions"[0x9A] MId=0x13C1 A=0x0] + + ctx.Menu = { MenuId = 0x13C1, TextId = 0x4A, PrevId = 0, NextId = 0, BackId = 0x13C0 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x9A, ValId = 0x13C3 } + + ctx.SelLine = 2 + lastGoodMenu = menuId + elseif (menuId==0x13D0) then + --M[Id=0x13D0 P=0x0 N=0x0 B=0x13C0 Text="Governor"[0xF2]] + --L[#0 T=LM_ori VId=0x13D1 Text="Governor"[0xF2] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0] + --L[#1 T=V_i8 VId=0x13D2 Text="Main Gear"[0x26D] Val=nil [1->255,170] MId=0x13D0 A=0x0] + --L[#2 T=V_i8 VId=0x13D3 Text="Pinion"[0x26C] Val=nil [1->255,20] MId=0x13D0 A=0x0] + --L[#3 T=V_i8 VId=0x13D5 Text="Low Throttle"[0xEA] Val=nil [1->100,75] MId=0x13D0 A=0x0] + --L[#4 T=V_i8 VId=0x13D6 Text="Filter"[0x1F1] Val=nil [1->65,35] MId=0x13D0 A=0x0] + --L[#5 T=M VId=0x13E0 Text="RPM Sensor"[0x26F] MId=0x13D0 A=0x0] + + + ctx.Menu = { MenuId = 0x13D0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13C0 } + ctx.MenuLines[0] = { Type = LINE_TYPE.LIST_MENU_ORI, TextId = 0x0F2, ValId = 0x13D1, Min=244, Max=245, Def=244, Val=0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26D, ValId = 0x13D2, Min=1, Max=255, Def=170, Val=170 } + ctx.MenuLines[2] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x26C, ValId = 0x13D3, Min=1, Max=255, Def=20, Val=20 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x0EA, ValId = 0x13D5, Min=1, Max=100, Def=75, Val=75 } + ctx.MenuLines[4] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1F1, ValId = 0x13D6, Min=1, Max=65, Def=35, Val=35 } + ctx.MenuLines[5] = { Type = LINE_TYPE.MENU, TextId = 0x26F, ValId = 0x13E0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x13E0) then + --M[Id=0x13E0 P=0x0 N=0x0 B=0x13D0 Text="Governor"[0xF2]] + --L[#0 T=LM_ori VId=0x13D1 Text="RPM Sensor"[0x26F] Val=nil NL=(0->1,0,S=244) [244->245,244] MId=0x13D0 A=0x0] + + ctx.Menu = { MenuId = 0x13E0, TextId = 0xF2, PrevId = 0, NextId = 0, BackId = 0x13D0 } + ctx.MenuLines[3] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0x26F, ValId = 0x13E3, Min=142, Max=143, Def=142, Val=0 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x1400) then + --M[Id=0x1400 P=0x0 N=0x0 B=0x1000 Text="SAFE"[0xDA]] + --L[#0 T=M VId=0x1410 Text="Stability"[0xDB] MId=0x1400 ] + --L[#1 T=M VId=0x140 Text="Panic"[0x8B] MId=0x1400 ] + --L[#2 T=M VId=0x1420 Text="Attitude Trim"[0x1E6] MId=0x1400 ] + + ctx.Menu = { MenuId = 0x1400, TextId = 0xDA, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xDB, ValId = 0x1410 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x8B, ValId = 0x140 } + ctx.MenuLines[2] = { Type = LINE_TYPE.MENU, TextId = 0x1E6, ValId = 0x1420 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1410) then + -- M[Id=0x1410 P=0x0 N=0x0 B=0x1400 Text="Stability"[0xDB]] + --L[#0 T=V_i8 VId=0x1411 Text="Gain"[0x43] val=50 [5->200,50] MId=0x1410 ] + --L[#1 T=V_i8 VId=0x1412 Text="Envelope"[0x1E7] val=45 [5->90,45] MId=0x1410 ] + --L[#3 T=V_nc VId=0x1413 Text="FLIGHT MODE"[0x8000] val=1 [0->5,0] MId=0x1410 ] + --L[#4 T=LM_tog VId=0x1414 Text="Stability"[0xDB] val=1 NL=(0->1,1,S=1) [1->2,1] MId=0x1410 ] + + ctx.Menu = { MenuId = 0x1410, TextId = 0xDB, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x43, ValId = 0x1411, Min=0, Max=200, Def=50, Val=50 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1E7, ValId = 0x1412, Min=0, Max=90, Def=45, Val=45 } + ctx.MenuLines[3] = { Type = LINE_TYPE.VALUE_NUM_I8_NC, TextId = 0x8000, ValId = 0x1413, Min=0, Max=5, Def=0, Val=1 } + ctx.MenuLines[4] = { Type = LINE_TYPE.LIST_MENU_TOG, TextId = 0xDB, ValId = 0x1414, Min=1, Max=2, Def=1, Val=1 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + + elseif (menuId==0x140) then + --M[Id=0x140 P=0x0 N=0x0 B=0x1400 Text="Panic"[0x8B]] + --L[#0 T=V_i8 VId=0x141 Text="Envelope"[0x1E7] val=30 [5->90,45] MId=0x140 ] + --L[#1 T=V_i8 VId=0x142 Text="Yaw"[0x42] val=30 [25->100,50] MId=0x140 ] + + ctx.Menu = { MenuId = 0x140, TextId = 0x8B, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x1E7, ValId = 0x141, Min=5, Max=90, Def=45, Val=30 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_I8, TextId = 0x42, ValId = 0x142, Min=25, Max=100, Def=50, Val=30 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1420) then + --M[Id=0x1420 P=0x0 N=0x0 B=0x1400 Text="Attitude Trim"[0x1E6]] + --L[#0 T=V_s16 VId=0x1421 Text="Roll"[0x40] val=274 [-850->850,450] MId=0x1420 ] + --L[#1 T=V_s16 VId=0x1422 Text="Pitch"[0x41] val=58 [-850->850,0] MId=0x1420 ] + + ctx.Menu = { MenuId = 0x1420, TextId = 0x1E6, PrevId = 0, NextId = 0, BackId = 0x1400 } + ctx.MenuLines[0] = { Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x40, ValId = 0x1421, Min=-850, Max=850, Def=450, Val=274 } + ctx.MenuLines[1] = { Type = LINE_TYPE.VALUE_NUM_SI16, TextId = 0x41, ValId = 0x1422, Min=-850, Max=850, Def=0, Val=58 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1700) then + --M[Id=0x1700 P=0x0 N=0x0 B=0x1000 Text="System Setup"[0x86]] + --L[#0 T=M VId=0x17F0 Text="Calibrate Sensor"[0xC7] MId=0x1700 ] + --L[#1 T=M VId=0x17E0 Text="Factory Reset"[0x97] MId=0x1700 ] + + ctx.Menu = { MenuId = 0x1700, TextId = 0x86, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.MenuLines[0] = { Type = LINE_TYPE.MENU, TextId = 0xC7, ValId = 0x17F0 } + ctx.MenuLines[1] = { Type = LINE_TYPE.MENU, TextId = 0x97, ValId = 0x17E0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x17E0) then + --M[Id=0x17E0 P=0x0 N=0x0 B=0x1700 Text="Factory Reset"[0x98]] + --[#3 T=M VId=0x17E1 Text="Apply"[0x90] MId=0x17E0 ] + + ctx.Menu = { MenuId = 0x17E0, TextId = 0x98, PrevId = 0, NextId = 0, BackId = 0x1700 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x90, ValId = 0x17E1 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x17F0) then + --M[Id=0x17F0 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]] + --L[#3 T=M VId=0x17F1 Text="Begin"[0x91] MId=0x17F0 ] + + ctx.Menu = { MenuId = 0x17F0, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x91, ValId = 0x17F1 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x17F1) then + --M[Id=0x17F1 P=0x0 N=0x0 B=0x1700 Text="Calibrate Sensor"[0xC7]] + --L[#3 T=M VId=0x17F1 Text="Complete"[0x93] MId=0x17F0 ] + + ctx.Menu = { MenuId = 0x17F1, TextId = 0xC7, PrevId = 0, NextId = 0, BackId = 0x1700 } + ctx.MenuLines[3] = { Type = LINE_TYPE.MENU, TextId = 0x93, ValId = 0x1700 } + + ctx.SelLine = 3 + lastGoodMenu = menuId + elseif (menuId==0x0001) then + -- Save Settings and Reboot + ctx.Menu = { MenuId = 0x0001, TextId = 0x009F, PrevId = 0, NextId = 0, BackId = 0x1000 } + ctx.SelLine = menuLib.BACK_BUTTON + else + ctx.Menu = { MenuId = 0x0002, Text = "NOT IMPLEMENTED", TextId = 0, PrevId = 0, NextId = 0, BackId = lastGoodMenu } + ctx.SelLine = menuLib.BACK_BUTTON + end + + menuLib.PostProcessMenu() +end + + +local function loadMenu(menuId) + menuLib.clearMenuLines() + local ctx = menuLib.DSM_Context + + if (menuId==0x1000) then + --M[Id=0x1000 P=0x0 N=0x0 B=0x0 Text="Main Menu"] + --L[#0 T=M VId=0x1010 val=nil [0->0,3] Text="Gyro settings" MId=0x1000 ] + --L[#1 T=M VId=0x105E val=nil [0->0,2] Text="Other settings" MId=0x1000 ] + + ctx.Menu = { MenuId = 0x1000, Text = "RX SIMULATION", PrevId = 0, NextId = 0, BackId = 0, TextId=0 } + ctx.MenuLines[0] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (NEW)", ValId = 0x1001,TextId=0 } + ctx.MenuLines[1] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "AR630/631/637 (INITIALIZED)", ValId = 0x1002, TextId=0 } + ctx.MenuLines[4] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX", ValId = 0x1005, TextId=0 } + ctx.MenuLines[5] = { MenuId = 0x1000, Type = LINE_TYPE.MENU, Text = "FC6250HX (UNLOCKED)", ValId = 0x1006, TextId=0 } + + ctx.SelLine = 0 + lastGoodMenu = menuId + elseif (menuId==0x1001) then + RX_Initialized = false + ctx.RX.Id = menuLib.RX.AR631 + ctx.RX.Name = "AR630/631/637-SIM" + ctx.RX.Version = "2.38.5" + RX_loadMenu = AR631_loadMenu + RX_loadMenu(0x01000) + elseif (menuId==0x1002) then + RX_Initialized = true + ctx.RX.Id = menuLib.RX.AR631 + ctx.RX.Name = "AR630/631/637-SIM" + ctx.RX.Version = "2.38.5" + RX_loadMenu = AR631_loadMenu + RX_loadMenu(0x01000) + elseif (menuId==0x1005) then + RX_Initialized = true + ctx.RX.Id = menuLib.RX.FC6250HX + ctx.RX.Name = "FC6250HX-SIM" + ctx.RX.Version = "5.6.255" + + RX_loadMenu = FC6250HX_loadMenu + RX_loadMenu(0x01000) + elseif (menuId==0x1006) then + RX_Initialized = false + ctx.RX.Id = menuLib.RX.FC6250HX + ctx.RX.Name = "FC6250HX-SIM" + ctx.RX.Version = "5.6.52" + + RX_loadMenu = FC6250HX_loadMenu + RX_loadMenu(0x01000) + end +end + + + + +local function SIM_Send_Receive() + local ctx = menuLib.DSM_Context + --if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + + if ctx.Phase == PHASE.RX_VERSION then -- request RX version + ctx.RX.Name = "SIMULATOR" + ctx.RX.Version = SIM_LIB_VERSION + ctx.Phase = PHASE.MENU_TITLE + ctx.Menu.MenuId=0 + + ctx.Refresh_Display = true + RX_loadMenu = loadMenu + + elseif ctx.Phase == PHASE.WAIT_CMD then + + elseif ctx.Phase == PHASE.MENU_TITLE then -- request menu title + if ctx.Menu.MenuId == 0 then -- First time loading a menu ? + RX_loadMenu(0x01000) + else + RX_loadMenu(ctx.Menu.MenuId) + end + ctx.Phase = PHASE.WAIT_CMD + ctx.Refresh_Display = true + + elseif ctx.Phase == PHASE.VALUE_CHANGING then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + ctx.Phase = PHASE.VALUE_CHANGING_WAIT + + elseif ctx.Phase == PHASE.VALUE_CHANGING_WAIT then + local line = ctx.MenuLines[ctx.SelLine] + + elseif ctx.Phase == PHASE.VALUE_CHANGE_END then -- send value + local line = ctx.MenuLines[ctx.SelLine] -- Updated Value of SELECTED line + if (DEBUG_ON) then Log.LOG_write("%3.3f %s: ", menuLib.getElapsedTime(), menuLib.phase2String(ctx.Phase)) end + if (DEBUG_ON) then Log.LOG_write("SEND SIM_updateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + if (DEBUG_ON) then Log.LOG_write("SEND SIM_validateMenuValue(ValueId=0x%X Text=\"%s\" Value=%s)\n", line.ValId, line.Text, menuLib.lineValue2String(line)) end + ctx.Phase = PHASE.WAIT_CMD + + elseif ctx.Phase == PHASE.EXIT then + ctx.Phase=PHASE.EXIT_DONE + end +end + +local FileState = {} + +-- Initial Setup +local function Sim_Init() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.INIT + + local ver, radio, maj, minor, rev, osname = getVersion() + if (osname==nil) then osname = "OpenTX" end -- OTX 2.3.14 and below returns nil + IS_EDGETX = string.sub(osname,1,1) == 'E' +end + +local function SIM_Done() + local ctx = menuLib.DSM_Context + ctx.Phase = PHASE.EXIT_DONE +end + + +local function SIM_Run() + if (menuLib.DSM_Context.Phase == PHASE.INIT) then + if (IS_EDGETX) then + menuLib.LoadTextFromFile(MSG_FILE,13) + menuLib.DSM_Context.Phase = PHASE.RX_VERSION + else -- Incremental initialization + lcd.clear() + lcd.drawText(30, 50, "Loading Msg file: "..(FileState.lineNo or 0)) + if (menuLib.INC_LoadTextFromFile(MSG_FILE, FileState)==1) then + menuLib.DSM_Context.Phase = PHASE.RX_VERSION + end + return + end + end + + return SIM_Send_Receive() +end + +return { init=Sim_Init, run=SIM_Run, done=SIM_Done } diff --git a/SCRIPTS/TOOLS/DSMLIB/MIN_msg_fwdp_en.txt b/SCRIPTS/TOOLS/DSMLIB/MIN_msg_fwdp_en.txt new file mode 100644 index 0000000..8d83314 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/MIN_msg_fwdp_en.txt @@ -0,0 +1,10 @@ +-- OVERRIDES Messges for MIN 128x64 screns +-- FORMAT || +-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX) +-- IMPORTANT: NO EMPTY LINES +-- +T |0x0097|DONT USE: Factory Reset +T |0x0098|DONT USE: Factory Reset +T |0x00A5|DONT USE: First Time Setup +T |0x0190|DONT USE: Relearn Servo Settings +T |0x020D|DONT USE: First Time SAFE Setup diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_1.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_1.png new file mode 100644 index 0000000..2fbc84d Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_1.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_2.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_2.png new file mode 100644 index 0000000..c458f03 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_2.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_3.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_3.png new file mode 100644 index 0000000..b9aef9a Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_3.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_4.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_4.png new file mode 100644 index 0000000..9427670 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_4.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_5.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_5.png new file mode 100644 index 0000000..2a526c3 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_5.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_6.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_6.png new file mode 100644 index 0000000..0d6e3d6 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_6.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_7.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_7.png new file mode 100644 index 0000000..f905abf Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_7.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_8.png b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_8.png new file mode 100644 index 0000000..38ca245 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_rx_pos_8.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120.png new file mode 100644 index 0000000..0858fb8 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120inv.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120inv.png new file mode 100644 index 0000000..7e7173e Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_120inv.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135.png new file mode 100644 index 0000000..8b06374 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135inv.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135inv.png new file mode 100644 index 0000000..656ec64 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_135inv.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140.png new file mode 100644 index 0000000..5058d97 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140inv.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140inv.png new file mode 100644 index 0000000..71faf52 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_140inv.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90.png new file mode 100644 index 0000000..88e8d2c Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90inv.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90inv.png new file mode 100644 index 0000000..b104f08 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_3_90inv.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/h_swp_norm.png b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_norm.png new file mode 100644 index 0000000..17e38cc Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/h_swp_norm.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_1.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_1.png new file mode 100644 index 0000000..032d602 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_1.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_10.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_10.png new file mode 100644 index 0000000..e755828 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_10.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_11.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_11.png new file mode 100644 index 0000000..66d1c2b Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_11.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_12.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_12.png new file mode 100644 index 0000000..1829cf2 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_12.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_13.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_13.png new file mode 100644 index 0000000..8f0bdfd Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_13.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_14.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_14.png new file mode 100644 index 0000000..7cc9f4c Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_14.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_15.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_15.png new file mode 100644 index 0000000..2823bb4 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_15.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_16.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_16.png new file mode 100644 index 0000000..3712971 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_16.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_17.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_17.png new file mode 100644 index 0000000..d3b82cb Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_17.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_18.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_18.png new file mode 100644 index 0000000..5dc3d73 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_18.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_19.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_19.png new file mode 100644 index 0000000..f37c0c5 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_19.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_2.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_2.png new file mode 100644 index 0000000..da0b814 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_2.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_20.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_20.png new file mode 100644 index 0000000..3ab286e Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_20.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_21.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_21.png new file mode 100644 index 0000000..2ef1d29 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_21.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_22.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_22.png new file mode 100644 index 0000000..4037dfe Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_22.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_23.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_23.png new file mode 100644 index 0000000..d767b2f Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_23.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_24.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_24.png new file mode 100644 index 0000000..ccc6b16 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_24.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_25.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_25.png new file mode 100644 index 0000000..ba84f61 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_25.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_3.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_3.png new file mode 100644 index 0000000..8510177 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_3.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_4.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_4.png new file mode 100644 index 0000000..75cb438 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_4.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_5.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_5.png new file mode 100644 index 0000000..5af94fe Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_5.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_6.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_6.png new file mode 100644 index 0000000..3668db1 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_6.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_7.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_7.png new file mode 100644 index 0000000..c7988c1 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_7.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_8.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_8.png new file mode 100644 index 0000000..4b0ea43 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_8.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_9.png b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_9.png new file mode 100644 index 0000000..948f858 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/rx_pos_9.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud.png new file mode 100644 index 0000000..e5c3684 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_1ele.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_1ele.png new file mode 100644 index 0000000..5546a25 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_1ele.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_2ele.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_2ele.png new file mode 100644 index 0000000..e96e406 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_1rud_2ele.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_1ele.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_1ele.png new file mode 100644 index 0000000..2f50424 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_1ele.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_2ele.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_2ele.png new file mode 100644 index 0000000..de03c4f Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_2rud_2ele.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron.png new file mode 100644 index 0000000..e8a406a Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron2.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron2.png new file mode 100644 index 0000000..6694f82 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_taileron2.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/tt_vtail.png b/SCRIPTS/TOOLS/DSMLIB/img/tt_vtail.png new file mode 100644 index 0000000..e8d1c08 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/tt_vtail.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail.png new file mode 100644 index 0000000..1611053 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail_1flp.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail_1flp.png new file mode 100644 index 0000000..b51d1fd Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_1ail_1flp.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail.png new file mode 100644 index 0000000..95686ff Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_1flp.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_1flp.png new file mode 100644 index 0000000..5b13f6c Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_1flp.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_2flp.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_2flp.png new file mode 100644 index 0000000..87b3842 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_2ail_2flp.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_elevon.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_elevon.png new file mode 100644 index 0000000..fa354ca Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_elevon.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/img/wt_flaperon.png b/SCRIPTS/TOOLS/DSMLIB/img/wt_flaperon.png new file mode 100644 index 0000000..82d2464 Binary files /dev/null and b/SCRIPTS/TOOLS/DSMLIB/img/wt_flaperon.png differ diff --git a/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt b/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt new file mode 100644 index 0000000..aa0cab0 --- /dev/null +++ b/SCRIPTS/TOOLS/DSMLIB/msg_fwdp_en.txt @@ -0,0 +1,437 @@ +-- FORMAT || +-- Line Type: Text for Menus (T), List_Text Options (LT), List_Text_Image (LI), Flight Mode (FM), RX Name (RX) +-- NO EMPTY LINES +-- Formmatting at end of line: /c=Center, /r=Right, /b=Bold, /m=menu +LT|0x0001|Off +LT|0x0002|On +-- Ihn/Act List Options +LT|0x0003|Inh +LT|0x0004|Act +-- +-- Channel selection for SAFE MODE and GAINS on FC6250HX +LT|0x000C|Inh +LT|0x000D|Ch5 +LT|0x000E|Ch6 +LT|0x000F|Ch7 +LT|0x0010|Ch8 +LT|0x0011|Ch9 +LT|0x0012|Ch10 +LT|0x0013|Ch11 +LT|0x0014|Ch12 +-- +-- Servo Output values +LT|0x002D|5.5ms +LT|0x002E|11ms +LT|0x002F|22ms +-- +-- Gain Multiplier Values +LT|0x0032|1 X +LT|0x0033|2 X +LT|0x0034|4 X +-- +LT|0x0035|Inh +LT|0x0036|Thr +LT|0x0037|Ail +LT|0x0038|Ele +LT|0x0039|Rud +LT|0x003A|Ch5 +LT|0x003B|Ch6 +LT|0x003C|Ch7 +LT|0x003D|Ch8 +LT|0x003E|Ch9 +LT|0x003F|Ch10 +LT|0x0040|Ch11 +LT|0x0041|Ch12 +LT|0x0042|Ch13 +LT|0x0043|Ch14 +LT|0x0044|Ch15 +LT|0x0045|Ch16 +LT|0x0046|Ch17 +LT|0x0047|Ch18 +LT|0x0048|Ch19 +LT|0x0049|Ch20 +-- +T |0x0040|Roll +T |0x0041|Pitch +T |0x0042|Yaw +T |0x0043|Gain/c/b +T |0x0045|Differential +T |0x0046|Priority +T |0x0049|Output Setup +T |0x004A|Failsafe +T |0x004B|Main Menu +T |0x004E|Position +-- +T |0x0050|Outputs +T |0x0051|Output Channel 1 +T |0x0052|Output Channel 2 +T |0x0053|Output Channel 3 +T |0x0054|Output Channel 4 +T |0x0055|Output Channel 5 +T |0x0056|Output Channel 6 +T |0x0057|Output Channel 7 +T |0x0058|Output Channel 8 +T |0x0059|Output Channel 9 +T |0x005A|Output Channel 10 +-- +-- FailSafe Options +--LT|0x005E|Inh +LT|0x005F|Hold Last +LT|0x0060|Preset +--LT|0x0061|Custom +-- +T |0x0071|Proportional +T |0x0072|Integral +T |0x0073|Derivate +T |0x0078|FM Channel +T |0x007F|Attitude Gain +-- +T |0x0080|Orientation +T |0x0082|Heading +T |0x0085|Frame Rate +T |0x0086|System Setup +T |0x0087|F-Mode Setup +T |0x0088|Enabled F-Modes +T |0x0089|Gain Channel +T |0x008A|Gain Sensitivity/r -- Right Align +T |0x008B|Panic +T |0x008E|Panic Delay +-- +LT|0x0187|No Freq --???? unset Freq +LT|0x0088|70hz +LT|0x0089|90hz +LT|0x008A|200hz +LT|0x008B|333hz +LT|0x008C|490hz +LT|0x008D|560hz +LT|0x008E|Normal +LT|0x008F|Reversed + +-- FC6250HX: Callibration +T |0x0090|Apply +T |0x0091|Begin +T |0x0092|Start +T |0x0093|Complete +T |0x0094|Done +-- +-- FC6250HX: Swashplate Type +-- +LT|0x0090|Normal +LI|0x0090|h_swp_norm.png|Normal +LT|0x0091|3 Servos 120 Y +LI|0x0091|h_swp_3_120.png|3 Servos 120 Y +LT|0x0092|3 Servos 120 Y-Inv +LI|0x0092|h_swp_3_120inv.png|3 Servos 120 Y-Inv +LT|0x0093|3 Servos 135 Y +LI|0x0093|h_swp_3_135.png|3 Servos 135 Y +LT|0x0094|3 Servos 135 Y-Inv +LI|0x0094|h_swp_3_135inv.png|3 Servos 135 Y-Inv +LT|0x0095|3 Servos 140 Y +LI|0x0095|h_swp_3_140.png|3 Servos 140 Y +LT|0x0096|3 Servos 140 Y-Inv +LI|0x0096|h_swp_3_140inv.png|3 Servos 140 Y-Inv +LT|0x0097|3 Servos 90 T +LI|0x0097|h_swp_3_90.png|3 Servos 90 T +LT|0x0098|3 Servos 90 T-Inv +LI|0x0098|h_swp_3_90inv.png|3 Servos 90 T-Inv +-- +T |0x0097|Factory Reset +T |0x0098|Factory Reset +T |0x0099|Advanced Setup +T |0x009A|Capture Failsafe Positions +T |0x009C|Custom Failsafe +-- +T |0x009F|Save Settings -- Save & Reboot RX +-- +T |0x00A5|First Time Setup +T |0x00AA|Capture Gyro Gains +T |0x00AD|Gain Channel Select +T |0x00AF|Dynamic +LT|0x00B0|Self-Level +LT|0x00B1|Envelope +-- +-- Flight Modes List Options +LT|0x00B5|Inh +LT|0x00B6|FM1 +LT|0x00B7|FM2 +LT|0x00B8|FM3 +LT|0x00B9|FM4 +LT|0x00BA|FM5 +LT|0x00BB|FM6 +LT|0x00BC|FM7 +LT|0x00BD|FM8 +LT|0x00BE|FM9 +LT|0x00BF|FM10 +-- +T |0x00BE|Unknown_BE -- Used in Reset menu (0x0001) while the RX is rebooting +-- +T |0x00C7|Calibrate Sensor +T |0x00C8|Sensor is Calibrating.. Wait +T |0x00CA|SAFE & Panic Mode Setup +-- +T |0x00CD|Level model & capt attitude/m -- SPECIAL MENU to itself who is not a comment +T |0x00CE|Error TX Conf +T |0x00CF|Invalid TX Ch Conf 1 +T |0x00D0|Invalid TX Ch Conf 2 +-- +-- RX Orientations for AR631/AR637, Optionally attach an Image + Alt Text to display +LT|0x00CB|Pos 1 +LI|0x00CB|rx_pos_1.png|Pilot View: RX Label Up, Pins Back +LT|0x00CC|Pos 2 +LI|0x00CC|rx_pos_2.png|Pilot View: RX Label Left, Pins Back +LT|0x00CD|Pos 3 +LI|0x00CD|rx_pos_3.png|Pilot View: RX Label Down, Pins Back +LT|0x00CE|Pos 4 +LI|0x00CE|rx_pos_4.png|Pilot View: RX Label Right, Pins Back +LT|0x00CF|Pos 5 +LI|0x00CF|rx_pos_5.png|Pilot View: RX Label UP, Pins to Front +LT|0x00D0|Pos 6 +LI|0x00D0|rx_pos_6.png|Pilot View: RX Label Left, Pins Front +LT|0x00D1|Pos 7 +LI|0x00D1|rx_pos_7.png|Pilot View: RX Label Down, Pins Front +LT|0x00D2|Pos 8 +LI|0x00D2|rx_pos_8.png|Pilot View: RX Label Right, Pins Front +LT|0x00D3|Pos 9 +LI|0x00D3|rx_pos_9.png|Pilot View: RX Label Up, Pins Left +LT|0x00D4|Pos 10 +LI|0x00D4|rx_pos_10.png|Pilot View: RX Label Back, Pins Left +LT|0x00D5|Pos 11 +LI|0x00D5|rx_pos_11.png|Pilot View: RX Label Down, Pins Left +LT|0x00D6|Pos 12 +LI|0x00D6|rx_pos_12.png|Pilot View: RX Label Front, Pins Left +LT|0x00D7|Pos 13 +LI|0x00D7|rx_pos_13.png|Pilot View: RX Label Up, Pins Right +LT|0x00D8|Pos 14 +LI|0x00D8|rx_pos_14.png|Pilot View: RX Label Back, Pins Right +LT|0x00D9|Pos 15 +LI|0x00D9|rx_pos_15.png|Pilot View: RX Label Down, Pins Right +LT|0x00DA|Pos 16 +LI|0x00DA|rx_pos_16.png|Pilot View: RX Label Front, Pins Right +LT|0x00DB|Pos 17 +LI|0x00DB|rx_pos_17.png|Pilot View: RX Label Back, Pins Down +LT|0x00DC|Pos 18 +LI|0x00DC|rx_pos_18.png|Pilot View: RX Label Left, Pins Down +LT|0x00DD|Pos 19 +LI|0x00DD|rx_pos_19.png|Pilot View: RX Label Front, Pins Down +LT|0x00DE|Pos 20 +LI|0x00DE|rx_pos_20.png|Pilot View: RX Label Right, Pins Down +LT|0x00DF|Pos 21 +LI|0x00DF|rx_pos_21.png|Pilot View: RX Label Back, Pins Up +LT|0x00E0|Pos 22 +LI|0x00E0|rx_pos_22.png|Pilot View: RX Label Left, Pins Up +LT|0x00E1|Pos 23 +LI|0x00E1|rx_pos_23.png|Pilot View: RX Label Front, Pins Up +LT|0x00E2|Pos 24 +LI|0x00E2|rx_pos_24.png|Pilot View: RX Label Right, Pins Up +LT|0x00E3|Pos Invalid +LI|0x00E3|rx_pos_25.png|Cannot detect orientation of RX +-- +-- RX Orientations images for FC5250 (HACK add 0x100 internally to differenciate for helis) +LI|0x01CB|h_rx_pos_1.png|Pilot View: RX Label Up, Pins Front +LI|0x01CC|h_rx_pos_2.png|Pilot View: RX Label Left, Pins Front +LI|0x01CD|h_rx_pos_3.png|Pilot View: RX Label Down, Pins Front +LI|0x01CE|h_rx_pos_4.png|Pilot View: RX Label Right, Pins Front +LI|0x01CF|h_rx_pos_5.png|Pilot View: RX Label UP, Pins to Back +LI|0x01D0|h_rx_pos_6.png|Pilot View: RX Label Left, Pins Back +LI|0x01D1|h_rx_pos_7.png|Pilot View: RX Label Down, Pins Back +LI|0x01D2|h_rx_pos_8.png|Pilot View: RX Label Right, Pins Back +-- +T |0x00D1|Receiver will Reboot/b +T |0x00D2|Panic Channel +T |0x00D3|Swashplate +T |0x00D5|Agility +T |0x00D8|Stop +T |0x00DA|SAFE/c/b -- Center + Bold +T |0x00DB|Stability +T |0x00DC|@ per sec +T |0x00DD|Tail rotor +T |0x00DE|Setup +T |0x00DF|AFR +T |0x00E0|Collective +T |0x00E1|Subtrim +T |0x00E2|Phasing +T |0x00E3|Pre-Comp +T |0x00E4|E-Ring +T |0x00E5|Swash Type +T |0x00E6|Travel +T |0x00E7|Left +T |0x00E8|Right +T |0x00EA|Low Throttle +-- +T |0x00F2|Governor +T |0x00F4|Soft Start +-- +LT|0x00F2|Fixed +LT|0x00F3|Adjustable +LT|0x00F4|Inh +LT|0x00F5|Nitro +-- +T |0x00F6|Direction +T |0x00F8|Settings -- ?? validate on a Spektrum radio +T |0x00F9|Gyro settings +T |0x00FE|Stick Priority/c/b +-- +T |0x0100|Make sure the model has been +T |0x0101|configured, including wing type, +T |0x0102|reversing, travel, trimmed, etc. +T |0x0103|before continuing setup. +T |0x0104| +T |0x0105| -- Blank +-- +T |0x0106|Any wing type, channel assignment, +T |0x0107|subtrim, or servo reversing changes +T |0x0108|require running through initial +T |0x0109|setup again. +T |0x010A| +T |0x010B| +-- +T |0x0190|Relearn Servo Settings +T |0x019C|Enter Receiver Bind Mode +T |0x01AA|Offset +T |0x01D7|SAFE Select Channel +T |0x01DC|AS3X/c/b -- Center + Bold +T |0x01DD|AS3X Settings +T |0x01DE|AS3X Gains +T |0x01E0|Rate Gains/c/b +T |0x01E2|SAFE Settings +T |0x01E3|SAFE Gains +T |0x01E6|Attitude Trim/c/b +T |0x01E7|Envelope +T |0x01E9|Roll Right +T |0x01EA|Roll Left +T |0x01EB|Pitch Down +T |0x01EC|Pitch Up +T |0x01EE|Thr to Pitch +T |0x01EF|Low Thr to Pitch/c/b +T |0x01F0|High Thr to Pitch/c/b +T |0x01F1|Filter +T |0x01F3|Threshold +T |0x01F4|Angle +T |0x01F6|Failsafe Angles/c/b +T |0x01F8|Safe Mode +T |0x01F9|SAFE Select +T |0x01FC|Panic F-Mode +T |0x01FD|FailSafe Flight Mode -- Safe Flight Mode +T |0x0201|Throttle +T |0x0204|Hover +T |0x0208|Decay +T |0x0209|Save to Backup +T |0x020A|Restore from Backup +T |0x020D|First Time SAFE Setup +-- +-- First time safe setup Page 3 : +T |0x020E|AS3X gains must be tuned +T |0x020F|and active in SAFE Flight Modes +T |0x0210|to help reduce wobble. +T |0x0211| +T |0x0212| +T |0x0213| -- Blank +-- +-- AS3X orientation Setting menu (Level) +T |0x021A|Set the model level, +T |0x021B|and press Continue. +T |0x021C| +T |0x021D| -- Blank +-- +-- AS3X orientation Setting menu (Nose down) +T |0x021F|Set the model on its nose, +T |0x0220|and press Continue. If the +T |0x0221|orientation on the next +T |0x0222|screen is wrong go back +T |0x0223|and try again. +T |0x0224|Continue +-- +T |0x0226|Angle Limits/c/b +T |0x0227|Other settings +T |0x0229|Set Orientation Manually +-- +-- Factory Default Warning +T |0x022B|WARNING! +T |0x022C|This will reset the +T |0x022D|configuration to factory +T |0x022E|defaults. This does not +T |0x022F|affect the backup config. +T |0x0230| -- Blank +-- +-- Backup Warning +T |0x0231|This will overwrite the +T |0x0232|backup memory with your +T |0x0233|current configuartion. +T |0x0234| +T |0x0235| -- Blank +-- +-- Restore from Backup Warning +T |0x0236|This will overwrite the +T |0x0237|current config with +T |0x0238|that which is in +T |0x0239|the backup memory. +T |0x023A| -- Blank +-- +-- Utilities Copy flight modes +T |0x023D|Copy F-Mode Settings +T |0x023E|Source F-Mode +T |0x023F|Target F-Mode +-- +T |0x0240|Utilities +-- +-- Gain Capture Page +T |0x024C|Gains will be captured on +T |0x024D|Captured gains will be +T |0x024E|Gains on +T |0x024F|were captured and changed +T |0x0250|from Adjustable to Fixed +-- +-- Utilities, Copy flight mode (Copy Confirmation, oveerriding FM) +T |0x0251|Are you sure you want to ovewrite the "Target" +T |0x0252|with the "Source" ? +T |0x0253| -- Blank +-- +T |0x0254|Pos = Up, Neg = Down +-- +-- First time safe setup Page 1 (maybe ask to select Flight Mode cannel) +T |0x0255|Before setting up SAFE +T |0x0256|a Flight Mode channel +T |0x0257|most be configured. +-- +-- First time safe setup Page 2 (something related for flight mode) +T |0x025A|Select the desired flight mode +T |0x025B|switch position to adjust settings +T |0x025C|for each flight mode +T |0x025D| +T |0x025E| -- Blank +-- +-- Utilities, Copy flight mode (Confirm) +T |0x0259|YES +T |0x0260|WARNING: "Target" +T |0x0261|F-Mode will be overwritten +T |0x0262|by "Source" +-- +T |0x0263|Fixed/Adjustable Gains/c/b +T |0x0266|Heading Gain/c/b +T |0x0267|Pos = Nose Up/Roll Right +T |0x0268|Neg = Nose Down/Roll Left +T |0x0269|SAFE - Thr to Pitch +T |0x026A|Use CAUTION for Yaw gain!/b +-- +T |0x026B|Head Speed +T |0x026C|Pinion +T |0x026D|Main Gear +T |0x026F|RPM Sensor +T |0x0272|Show Advanced Menus +-- +T |0x0300|No compatible DSM RX... +T |0x0301|Waiting for RX to Restart +-- +FM|0x8000|Flight Mode/c/b +-- +RX|0x0001|AR636 +RX|0x0014|SPM4651T +RX|0x0015|AR637T +RX|0x0016|AR637TA +RX|0x0018|FC6250HX +RX|0x0019|AR630 +RX|0x001A|AR8360T +RX|0x001B|AR8020T +RX|0x001C|AR10360T +RX|0x001E|AR631 + diff --git a/SCRIPTS/TOOLS/DSM_AR636_Tel.lua b/SCRIPTS/TOOLS/DSM_AR636_Tel.lua new file mode 100644 index 0000000..0ec740d --- /dev/null +++ b/SCRIPTS/TOOLS/DSM_AR636_Tel.lua @@ -0,0 +1,683 @@ +local toolName = "TNS|DSM AR636 Telemetry|TNE" +---- ######################################################################### # +---- # 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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- Developer: Francisco Arzu +-- Original idea taken from DsmPID.lua.. don't know who is the author +-- + +local DEBUG_ON = false +-- + +local TEXT_SIZE = 0 -- NORMAL +local X_COL1_HEADER = 6 +local X_COL1_DATA = 60 +local X_COL2_HEADER = 170 +local X_COL2_DATA = 220 +local Y_LINE_HEIGHT = 20 +local Y_HEADER = 0 +local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2 +local X_DATA_LEN = 80 +local X_DATA_SPACE = 5 + + +local function getPage(iParam) + -- get page from 0-based index + -- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2) + local res = (math.floor(iParam/4)==0) and 0 or 1 + return res +end + +local function round(v) + -- round float + local factor = 100 + return math.floor(v * factor + 0.5) / factor +end + + +local function readValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + --v = round(v) + return v +end + +local function readValueById(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return nil end + + local v = getValue(i.id) + return v +end + + + +local function readBatValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + if (v==nil) then return "--" end + + return string.format("%2.2f",v) +end + +local function readActiveParamValue(sensor) + -- read and return a validated active parameter value + local v = getValue(sensor) + if (v<1 or v>8) then + return -1 + end + return v +end + + +local function drawPIDScreen() + -- draw labels and params on screen + + local pageId = getValue("FLss") + + lcd.clear() + -- if active gain does not validate then assume + -- Gain Adjustment Mode is disabled + if not (pageId==4401 or pageId==4402) then + lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Gain Adjustment Mode",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/R + Low/R + Panic (3 sec)",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE) + return + end + + local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base + + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS) + lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS) + + + + local p = readValue("FdeA") + local i = readValue("FdeB") + local d = readValue("FdeL") + local r = readValue("FdeR") + + local titles = {[0]="P:", "I:", "D:", "Resp:", "P:","I:","D:", "Filt:"} + local values = {[0]=p,i,d,r,p,i,d,r} + + local activeParam = readActiveParamValue("Hold")-1 + + for iParam=0,7 do + -- highlight selected parameter + local attr = (activeParam==iParam) and INVERS or 0 + -- circular index (per page) + local perPageIndx = (iParam % 4) + + -- set y draw coord + local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA + + -- check if displaying cyclic params. + local isCyclicPage = (getPage(iParam)==0) + + -- labels + local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER + -- labels are P,I,D for both pages except for last param + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + -- gains + -- set all params for non-active page to '--' rather than 'last value' + val = (getPage(iParam)==activePage) and values[iParam] or '--' + x = isCyclicPage and X_COL1_DATA or X_COL2_DATA + + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + end +end + + +local function drawFlightLogScreen() + -- draw labels and params on screen + local h = getValue("Hold") + local activeParam = h-1 -- H + + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS) + + -- read and return parameters + local a = getValue("FdeA") + local b = getValue("FdeB") + local l = getValue("FdeL") + local r = getValue("FdeR") + local f = getValue("FLss") + + local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"} + local values = {[0]=a,b,l,r,f,h} + + local y = Y_LINE_HEIGHT+Y_DATA + + for iParam=0,3 do -- A,B,L,R + -- highlight selected parameter (rund) + local attr = ((activeParam%4)==iParam) and INVERS or 0 + -- labels + local x = X_COL1_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + -- Values + val = values[iParam] + x = X_COL1_DATA + X_DATA_LEN + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT) + end + + y = y + Y_LINE_HEIGHT + end + + y = Y_LINE_HEIGHT+Y_DATA + for iParam=4,5 do -- F, H + -- labels + local x = X_COL2_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE + BOLD) + + -- Values + val = values[iParam] + x = X_COL2_DATA + X_DATA_LEN + lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD) + + y = y + Y_LINE_HEIGHT + end + + -- Bat + y = y + Y_LINE_HEIGHT + local bat = readBatValue("A2") or "--" + lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE) + lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT) + lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE) + +end + +local function servoAdjustScreen() + -- draw labels and params on screen + local pageId = getValue("FLss") -- FLss + local activeParam = getValue("Hold")-1 -- Hold + + lcd.clear() + lcd.drawText (0, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS) + + if pageId~=1234 then + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*1,"Enter Servo Adjustment Mode",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*2,"Stk: Low/L + Low/R + Panic (3 sec)",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE) + lcd.drawText(X_COL1_HEADER,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE) + return + end + + local a = getValue("FdeA") + local b = getValue("FdeB") + local l = getValue("FdeL") + + local titles = {[0]="Servo1:", "Servo2:", "Servo3:"} + local values = {[0]=a,b,l} + + for iParam=0,#values do -- S1,S2,S3 + -- highlight selected parameter + local attr = (activeParam==iParam) and INVERS or 0 + + -- set y draw coord + local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER + + -- labels + local x = X_COL1_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] + x = X_COL1_DATA + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + end +end + +local function Unsigned_to_SInt16(value) + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function getDegreesValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%0.1f o",vs/10) +end + + +local function getDecHexValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%d (0x%04X)",vs,v) +end + + + + +local function drawVersionScreen() + local paramV = getValue("FdeA") + local B = getValue("FdeB") + local rxId = getValue("FdeL") + local firmware = getValue("FLss") + local prodId = getValue("Hold") + local bat = readBatValue("A2") + + lcd.clear() + lcd.drawText (0, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS) + + --Product ID + local val = "ID_".. prodId + + if (prodId==243) then val = "Blade 230 V1" + elseif (prodId==250) then val = "Blade 230 V2 (not Smart)" + elseif (prodId==149) then val = "Blade 250 CFX" + end + + local y = Y_DATA + local x_data1 = X_COL1_DATA+X_DATA_LEN + lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE) + lcd.drawText (x_data1, y, val, TEXT_SIZE) + + -- RX + val = "ID_"..rxId + if (rxId==1) then val = "AR636" + end + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE) + lcd.drawText (x_data1, y, val, TEXT_SIZE) + + -- Firmware + val = string.format("%0.2f",firmware/100) + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE) + lcd.drawText (x_data1, y, val, TEXT_SIZE) + + -- ParamV + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE) + lcd.drawText (x_data1, y, paramV, TEXT_SIZE) + + -- Bat + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE) + lcd.drawText (x_data1, y, bat, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText(X_COL1_HEADER,y,"Press Panic for 3s",TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText(X_COL1_HEADER,y,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE) + +end + +local function parseFlightMode(v) + -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=??? + if v==nil then return "---" end + local fm = bit32.rshift(v, 12) + local status = bit32.band(bit32.rshift(v, 8),0xF) + + local res = " "..fm.." " + + if (fm==0) then res = res .. " NORMAL" + elseif (fm==1) then res = res .. " INTERMEDIATE" + elseif (fm==2) then res = res .. " ADVANCED" + elseif (fm==5) then res = res .. " PANIC" + end + + if (status==2) then res=res .. " HOLD" end + + if (DEBUG_ON) then + res = res .. string.format(" (0x%04X)",v) + end + + return res +end + + +local function drawAlpha6Monitor() + lcd.clear() + + local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=??? + + local ARoll = getDegreesValue("2406") --Att Roll + local APitch = getDegreesValue("2408") --Att Pitch + local AYaw = getDegreesValue("240B") --Att Yaw + + + lcd.drawText (0,0, "BLADE Alpha6 Monitor", TEXT_SIZE+INVERS) + + local y = Y_DATA + local x_data1 = X_COL1_DATA+X_DATA_LEN + local x_data2 = X_COL1_DATA+X_DATA_LEN*2 + local x_data3 = X_COL1_DATA+X_DATA_LEN*3 + + -- Flight Mode + lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText (x_data1,y, "Attitude", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (x_data2,y, "Gyro", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (x_data3,y, "Gain", TEXT_SIZE+BOLD + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Rol:", TEXT_SIZE) + lcd.drawText (x_data1,y, ARoll, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE) + lcd.drawText (x_data1,y, APitch, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE) + lcd.drawText (x_data1,y, AYaw, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT + lcd.drawText (0,y, "Bat: "..readBatValue("A2").." v", TEXT_SIZE) + + + -- Debug Values + if (DEBUG_ON) then + local s2400 = getDecHexValue("2400") + local s2402 = getDecHexValue("2402") + local s2404 = getDecHexValue("2404") + + local s240D = getDecHexValue("240D") + + local s1G00 = getDecHexValue("1G00") + local s1G02 = getDecHexValue("1G02") + local s1G04 = getDecHexValue("1G04") + local s1G06 = getDecHexValue("1G06") + local s1G08 = getDecHexValue("1G08") + local s1G0B = getDecHexValue("1G0B") + local s1G0D = getDecHexValue("1G0D") + + local titles = {[0]= + "2400","2402/FM-S-?", + "2404","240D", + "1G00","1G02","1G04", + "1G06","1G08","1G0B","1G0D"} + + local values = {[0]= + s2400,s2402,s2404,s240D, + s1G00,s1G02,s1G04, + s1G06,s1G08,s1G0B,s1G0D} + + + -- draw labels and params on screen + + y = Y_LINE_HEIGHT*2 + Y_HEADER + for iParam=0,#titles do -- ?? + -- labels + local x = X_COL1_HEADER+220 + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] + x = X_COL1_DATA+250 + lcd.drawText (x, y, val, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + end + end +end + +local function readAlpha3arameters() + +end + + + + +local function drawAS3XMonitor() + lcd.clear() + local s1G00 = getDecHexValue("1G00") + local s1G02 = getDecHexValue("1G02") + local s1G04 = getDecHexValue("1G04") + local s1G06 = getDecHexValue("1G06") + local s1G08 = getDecHexValue("1G08") + local s1G0B = getDecHexValue("1G0B") + local s1G0D = getDecHexValue("1G0D") + + local s6C00 = getDecHexValue("6C00") + local s6C02 = getDecHexValue("6C02") + local s6C04 = getDecHexValue("6C04") + + + + local RRoll = bit32.rshift(getValue("1G00") or 0,8) + local RPitch = bit32.band(getValue("1G00") or 0,0xFF) + local RYaw = bit32.rshift(getValue("1G02") or 0,8) + + local HRoll = bit32.band(getValue("1G02") or 0,0xFF) + local HPitch = bit32.rshift(getValue("1G04") or 0,8) + local HYaw = bit32.band(getValue("1G04") or 0,0xFF) + + local ARoll = bit32.rshift(getValue("1G06") or 0,8) + local APitch = bit32.band(getValue("1G06") or 0,0xFF) + local AYaw = bit32.rshift(getValue("1G08") or 0,8) + + + lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS) + + local y = Y_DATA + local x_data1 = X_COL1_DATA+X_DATA_LEN + local x_data2 = X_COL1_DATA+X_DATA_LEN*2 + local x_data3 = X_COL1_DATA+X_DATA_LEN*3.1 + + -- Flight Mode + --lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText (x_data1,y, "Rate", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (x_data2,y, "Head", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (x_data3+X_DATA_SPACE*3,y, "Actual", TEXT_SIZE+BOLD + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Roll %:", TEXT_SIZE) + lcd.drawText (x_data1,y, RRoll, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, HRoll, TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, ARoll, TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Pitch %:", TEXT_SIZE) + lcd.drawText (x_data1,y, RPitch, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, HPitch, TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, APitch, TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Yaw %:", TEXT_SIZE) + lcd.drawText (x_data1,y, RYaw, TEXT_SIZE + RIGHT) + lcd.drawText (x_data2,y, HYaw, TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, AYaw, TEXT_SIZE + RIGHT) + + + -- Debug Values + if (DEBUG_ON) then + local Alpha3Tags = {[0]= + "1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"} + + local params = {[0]= + s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 } + + y = Y_LINE_HEIGHT*2 + Y_HEADER + for iParam=0,#Alpha3Tags do -- ?? + -- labels + local x = X_COL1_HEADER+220 + local val = Alpha3Tags[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = params[iParam] + x = X_COL1_DATA+250 + lcd.drawText (x, y, val, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + end + end +end + +local function openTelemetryRaw(i2cId) + --Init telemetry (Spectrun Telemetry Raw STR) + multiBuffer( 0, string.byte('S') ) + multiBuffer( 1, string.byte('T') ) + multiBuffer( 2, string.byte('R') ) + multiBuffer( 3, i2cId ) -- Monitor this teemetry data + multiBuffer( 4, 0 ) -- Allow to get Data +end + +local function closeTelemetryRaw() + multiBuffer(0, 0) -- Destroy the STR header + multiBuffer(3, 0) -- Not requesting any Telementry ID +end + +local lineText = {nil} +local I2C_TEXT_GEN = 0x0C + +local function drawTextGen(event) + if (multiBuffer(0)~=string.byte('S')) then -- First time run??? + openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN + lineText = {nil} + end + + -- Proces TEXT GEN Telementry message + if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received + local instanceNo = multiBuffer( 5 ) + local lineNo = multiBuffer( 6 ) + local line = "" + for i=0,13 do + line = line .. string.char(multiBuffer( 7 + i )) + end + + multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message + lineText[lineNo]=line + end + + lcd.clear() + -- Header + if (lineText[0]) then + lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS) + else + lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS) + end + + -- Menu lines + local y = Y_DATA + for i=1,8 do + if (lineText[i]) then + lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE) + end + y = y + Y_LINE_HEIGHT + end + + if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data + closeTelemetryRaw() + end +end + +local telPage = 1 +local telPageSelected = 0 +local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade Alpha6 Monitor", "Plane AS3X Monitor", "TextGen", "Flight Log"} + +local function drawMainScreen(event) + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (AR636)", TEXT_SIZE + INVERS) + + for iParam=1,#pageTitle do + -- highlight selected parameter + local attr = (telPage==iParam) and INVERS or 0 + + -- set y draw coord + local y = (iParam-1)*Y_LINE_HEIGHT+Y_DATA + + -- labels + local x = X_COL1_HEADER + local val = pageTitle[iParam] + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + + if event == EVT_VIRTUAL_PREV then + if (telPage>1) then telPage = telPage - 1 end + elseif event == EVT_VIRTUAL_NEXT then + if (telPage<#pageTitle) then telPage = telPage + 1 end + elseif event == EVT_VIRTUAL_ENTER then + telPageSelected = telPage + end +end + + +local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawTextGen, drawFlightLogScreen} + +local function run_func(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + -- draw specific page + pageDraw[telPageSelected](event) + + if event == EVT_VIRTUAL_EXIT then + if (telPageSelected==0) then return 1 end -- on Main?? Exit Script + telPageSelected = 0 -- any page, return to Main + end + + return 0 +end + +local function init_func() + + if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens + TEXT_SIZE = SMLSIZE + X_COL1_HEADER = 0 + X_COL1_DATA = 20 + + X_COL2_HEADER = 60 + X_COL2_DATA = 90 + + X_DATA_LEN = 28 + X_DATA_SPACE = 1 + + + Y_LINE_HEIGHT = 8 + Y_DATA = Y_HEADER + Y_LINE_HEIGHT + + end +end + +return { run=run_func, init=init_func } diff --git a/SCRIPTS/TOOLS/DSM_SmartRX_Tel.lua b/SCRIPTS/TOOLS/DSM_SmartRX_Tel.lua new file mode 100644 index 0000000..716f308 --- /dev/null +++ b/SCRIPTS/TOOLS/DSM_SmartRX_Tel.lua @@ -0,0 +1,603 @@ +local toolName = "TNS|DSM Smart RX Telemetry|TNE" +---- ######################################################################### # +---- # 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. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- Developer: Francisco Arzu + + +local DEBUG_ON = false +-- + +local TEXT_SIZE = 0 -- NORMAL +local X_COL1_HEADER = 6 +local X_COL1_DATA = 60 +local X_COL2_HEADER = 170 +local X_COL2_DATA = 220 +local Y_LINE_HEIGHT = 20 +local Y_HEADER = 0 +local Y_DATA = Y_HEADER + Y_LINE_HEIGHT*2 +local X_DATA_LEN = 80 +local X_DATA_SPACE = 5 + + + + +local function getPage(iParam) + -- get page from 0-based index + -- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2) + local res = (math.floor(iParam/4)==0) and 0 or 1 + return res +end + +local function round(v) + -- round float + local factor = 100 + return math.floor(v * factor + 0.5) / factor +end + + +local function readValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + --v = round(v) + return v +end + +local function readValueById(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return nil end + + local v = getValue(i.id) + return v +end + + + +local function readBatValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + if (v==nil) then return v end + + return string.format("%2.2f",v) +end + +local function readActiveParamValue(sensor) + -- read and return a validated active parameter value + local v = getValue(sensor) + if (v<1 or v>8) then + return -1 + end + return v +end + + + +local function drawFlightLogScreen(event) + -- draw labels and params on screen + local h = getValue("Hold") + local activeParam = h-1 -- H + + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS) + + -- read and return parameters + local a = getValue("FdeA") + local b = getValue("FdeB") + local l = getValue("FdeL") + local r = getValue("FdeR") + local f = getValue("FLss") + + local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"} + local values = {[0]=a,b,l,r,f,h} + + local y = Y_LINE_HEIGHT+Y_DATA + + for iParam=0,3 do -- A,B,L,R + -- highlight selected parameter (rund) + local attr = ((activeParam%4)==iParam) and INVERS or 0 + -- labels + local x = X_COL1_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + -- Values + val = values[iParam] + x = X_COL1_DATA + X_DATA_LEN + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE + RIGHT) + end + + y = y + Y_LINE_HEIGHT + end + + y = Y_LINE_HEIGHT+Y_DATA + for iParam=4,5 do -- F, H + -- labels + local x = X_COL2_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE + BOLD) + + -- Values + val = values[iParam] + x = X_COL2_DATA + X_DATA_LEN + lcd.drawText (x, y, val, TEXT_SIZE + RIGHT + BOLD) + + y = y + Y_LINE_HEIGHT + end + + -- Bat + y = y + Y_LINE_HEIGHT + local bat = readBatValue("A2") or "--" + lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE) + lcd.drawText (X_COL2_DATA + X_DATA_LEN, y, bat, TEXT_SIZE + RIGHT) + lcd.drawText (X_COL2_DATA + X_DATA_LEN + X_DATA_SPACE, y, "v", TEXT_SIZE) + + +end + + + + + + +local function Unsigned_to_SInt16(value) + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function getDegreesValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%0.1f o",vs/10) +end + + +local function getDecHexValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%d (0x%04X)",vs,v) +end + +local as3xData = {[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +local function drawAS3XSettings(event, page) + local s0500 = getDecHexValue("0500") + local s0502 = getDecHexValue("0502") + local s0504 = getDecHexValue("0504") + local s0506 = getDecHexValue("0506") + local s0508 = getDecHexValue("0508") + local s050B = getDecHexValue("050B") + local s050D = getDecHexValue("050D") + + local d0500 = readValueById("0500") or 0 + local flags = bit32.rshift(d0500,8) + local state = bit32.band(d0500,0xFF) + + local flagsMsg="" + -- flags bits: Safe Envelop, ?, Angle Demand, Stab + if (bit32.band(flags,0x1)~=0) then flagsMsg=flagsMsg.."AS3X Stab" end + -- This one, only one should show + if (bit32.band(flags,0x2)~=0) then flagsMsg=flagsMsg..", Angle Demand" + elseif (bit32.band(flags,0x8)~=0) then flagsMsg=flagsMsg..", Safe Envelope" + elseif (bit32.band(flags,0x4)~=0) then flagsMsg=flagsMsg..", AS3X Heading" end + + local d0502 = readValueById("0502") or 0 -- 0x?F?S + local fm = bit32.band(bit32.rshift(d0502,8),0xF) -- 0,1,2 + + local axis = bit32.band(d0502,0xF) -- 0=Gains,1=Headings,2=Angle Limits (cointinus iterating to provide all values) + + local d0504 = readValueById("0504") or 0 + local d0506 = readValueById("0506") or 0 + local d0508 = readValueById("0508") or 0 + + local d0 = bit32.rshift(d0504,8) + local d1 = bit32.band(d0504,0xFF) + local d2 = bit32.rshift(d0506,8) + local d3 = bit32.band(d0506,0xFF) + local d4 = bit32.rshift(d0508,8) + local d5 = bit32.band(d0508,0xFF) + + --axis: 0=Gains+Headings (RG,PG,YG,RH,PH,YH), 1=Safe Gains (R,P,Y),2=Angle Limits(L,R,U,D) + --Constantly changing from 0..2 to represent different data, thats why we have to store the values + --in a script/global variable, and not local to the function + local s = axis*6 + as3xData[s+0] = d0 + as3xData[s+1] = d1 + as3xData[s+2] = d2 + as3xData[s+3] = d3 + as3xData[s+4] = d4 + as3xData[s+5] = d5 + + + lcd.clear() + lcd.drawText (0,0, "AS3X/SAFE Settings", TEXT_SIZE + INVERS) + + local y = Y_DATA + -- Flight Mode + lcd.drawText (X_COL1_HEADER,y, "FM: "..(fm+1), TEXT_SIZE) + lcd.drawText (X_COL1_DATA+X_DATA_LEN*0.3,y, "Flags: "..flags, TEXT_SIZE) + lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "State: "..state, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, flagsMsg, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + + if (page==1) then + lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "AS3X Gains", TEXT_SIZE+BOLD) + lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.3,y, "AS3X Headings", TEXT_SIZE+BOLD) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[0], TEXT_SIZE + RIGHT) -- Roll G + lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[3], TEXT_SIZE + RIGHT) -- Roll H + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA+X_DATA_LEN,y,as3xData[1], TEXT_SIZE + RIGHT) -- Pitch G + lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[4], TEXT_SIZE + RIGHT) -- Pitch H + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA+X_DATA_LEN,y, as3xData[2], TEXT_SIZE + RIGHT) -- Yaw G + lcd.drawText (X_COL2_DATA+X_DATA_LEN,y, as3xData[5], TEXT_SIZE + RIGHT) -- Yaw H + end + + + if (page==2) then + local x_data1 = X_COL1_DATA+X_DATA_LEN + local x_data2 = X_COL2_HEADER+X_DATA_LEN*1.6 + + lcd.drawText (X_COL1_HEADER+X_DATA_LEN*0.3,y, "SAFE Gains", TEXT_SIZE+BOLD) + lcd.drawText (X_COL2_HEADER+X_DATA_LEN*0.1,y, "Angle Limits", TEXT_SIZE+BOLD) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Roll:", TEXT_SIZE) + lcd.drawText (x_data1,y, as3xData[6], TEXT_SIZE + RIGHT) + + lcd.drawText (X_COL2_HEADER,y, "Roll R:", TEXT_SIZE) + lcd.drawText (x_data2,y, as3xData[12], TEXT_SIZE + RIGHT) + + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Pitch:", TEXT_SIZE) + lcd.drawText (x_data1,y,as3xData[7], TEXT_SIZE + RIGHT) + + lcd.drawText (X_COL2_HEADER,y, "Roll L:", TEXT_SIZE) + lcd.drawText (x_data2,y,as3xData[13], TEXT_SIZE + RIGHT) + + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER,y, "Yaw:", TEXT_SIZE) + lcd.drawText (x_data1,y, as3xData[8], TEXT_SIZE + RIGHT) + + lcd.drawText (X_COL2_HEADER,y, "Pitch U:", TEXT_SIZE) + lcd.drawText (x_data2,y, as3xData[14], TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL2_HEADER,y, "Pitch D:", TEXT_SIZE) + lcd.drawText (x_data2,y, as3xData[15], TEXT_SIZE + RIGHT) + end + + -- Debug Values + if (DEBUG_ON) then + local titles = {[0]= + "0500","0502","0504","0506","0508","050B","050D"} + + local values = {[0]= + s0500,s0502,s0504,s0506,s0508,s050B,s050D } + + y = Y_LINE_HEIGHT*2 + Y_HEADER + for iParam=0,#titles do -- ?? + -- labels + local x = X_COL1_HEADER+250 + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] or "--" + x = X_COL1_DATA+250 + lcd.drawText (x, y, val, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + end + end +end + +local function drawAS3XSettingsP1(event) + drawAS3XSettings(event, 1) +end + +local function drawAS3XSettingsP2(event) + drawAS3XSettings(event, 2) +end + + +local function doFloat(v) + if v==nil then return 0.0 end + + local vs = string.format("%1.2f",v) + + return vs + 0.0 +end + + +local ESC_Title={[0]="","RPM:","Volts:","Motor:","Mot Out:","Throttle:","FET Temp:", "BEC V:", "BEC T:", "BEC A:"} +local ESC_uom={[0]="","","V","A","%","%","C", "V","C","A"} +local ESC_Status={[0]=0,0,0,0,0,0,0,0,0,0,0} +local ESC_Min={[0]=0,0,0,0,0,0,0,0,0,0,0} +local ESC_Max={[0]=0,0,0,0,0,0,0,0,0,0,0} + +local function drawESCStatus(event) + lcd.clear() + ESC_Status[1] = getValue("Erpm") -- RPM + ESC_Status[2] = doFloat(getValue("EVIN")) -- Volts + ESC_Status[3] = doFloat(getValue("ECUR")) -- Current + ESC_Status[4] = doFloat(getValue("EOUT")) -- % Output + ESC_Status[5] = doFloat(getValue("ETHR")) -- Throttle % (EOUT) + ESC_Status[6] = getValue("TFET") -- Temp FET + + ESC_Status[7] = doFloat(getValue("VBEC")) -- Volts BEC + ESC_Status[8] = getValue("TBEC") -- Temp BEC + ESC_Status[9] = doFloat(getValue("CBEC")) -- Current BEC + + for i=1,9 do + if (ESC_Status~=nil) then + if (ESC_Min[i]==0) then + ESC_Min[i]=ESC_Status[i] + else + ESC_Min[i] = math.min(ESC_Min[i],ESC_Status[i]) + end + + ESC_Max[i] = math.max(ESC_Max[i],ESC_Status[i]) + end + end + + lcd.drawText (0,0, "ESC", TEXT_SIZE+INVERS) + + local y = 0 + local x_data = X_COL1_DATA+X_DATA_LEN*1.5 + local x_data2 = X_COL2_DATA+X_DATA_LEN*0.5 + local x_data3 = x_data2 + X_DATA_LEN*0.8 + + + lcd.drawText (x_data,y , "Status", TEXT_SIZE+BOLD+RIGHT) + lcd.drawText (x_data2,y, "Min", TEXT_SIZE+BOLD+RIGHT) + lcd.drawText (x_data3,y, "Max", TEXT_SIZE+BOLD+RIGHT) + + y = Y_DATA + for i=1,9 do + lcd.drawText (X_COL1_HEADER,y, ESC_Title[i], TEXT_SIZE + BOLD) + + lcd.drawText (x_data,y, ESC_Status[i] or "--", TEXT_SIZE + RIGHT) + lcd.drawText (x_data + X_DATA_SPACE,y, ESC_uom[i], TEXT_SIZE) + + lcd.drawText (x_data2,y, ESC_Min[i] or "--", TEXT_SIZE + RIGHT) + lcd.drawText (x_data3,y, ESC_Max[i] or "--", TEXT_SIZE + RIGHT) + y = y + Y_LINE_HEIGHT + end +end + + +local function drawBATStatus(event) + local Title={[0]="","Bat:","Temp:","Rem :","Curr:","Used:","Imbal:","Cycles:", "RX:", "BCpT?:"} + local uom={[0]="","V","C","%","mAh","mAh","mV","", "V",""} + local Values={[0]=0,0,0,0,0,0,0,0,0,0,0} + local CellValues={[0]=0,0,0,0,0,0,0,0,0,0,0} + + lcd.clear() + + local ESC_Volts = getValue("EVIN") or 0 -- Volts + local ESC_Current = getValue("ECUR") or 0 -- Current + + Values[1] = 0 -- compute later + Values[2] = getValue("BTmp") -- Current (C) + Values[3] = nil -- Remaining??? + Values[4] = getValue("BCur") -- Current (mAh) + Values[5] = getValue("BUse") -- Current Used (mAh) + Values[6] = getValue("CLMa") -- 0.0 (mV) Imbalance + Values[7] = getValue("Cycl") -- Cycles + Values[8] = readBatValue("A2") -- v + Values[9] = getValue("BCpT") -- Current (mAh) ???? + + + --- Total Voltange Calculation + local VTotal=0 + for i=1,10 do + CellValues[i] = getValue("Cel"..i) + VTotal = VTotal + CellValues[i] + end + + if (VTotal==0) then -- No Inteligent Battery,use intelligent ESC if any + VTotal = ESC_Volts + Values[4] = string.format("%d",ESC_Current * 1000) + end + + Values[1] = string.format("%2.2f",VTotal) + + --- SCREEN + + lcd.drawText (X_COL1_HEADER,0, "Battery Stats", TEXT_SIZE+INVERS) + + + + local y = Y_DATA + local x_data = X_COL1_DATA+X_DATA_LEN+X_DATA_SPACE*3 + for i=2,9 do + lcd.drawText (X_COL1_HEADER, y, Title[i], TEXT_SIZE + BOLD) + lcd.drawText (x_data, y, Values[i] or "--", TEXT_SIZE + RIGHT) + lcd.drawText (x_data+X_DATA_SPACE, y, uom[i], TEXT_SIZE) + y = y + Y_LINE_HEIGHT + end + + y = Y_DATA + x_data = X_COL2_DATA+X_DATA_LEN+X_DATA_SPACE*5 + for i=1,8 do + if ((CellValues[i] or 0) > 0) then + lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,y, "Cel "..i..":", TEXT_SIZE + BOLD) + lcd.drawText (x_data,y, string.format("%2.2f",CellValues[i] or 0), TEXT_SIZE + RIGHT) + lcd.drawText (x_data+X_DATA_SPACE,y, "v", TEXT_SIZE) + end + y = y + Y_LINE_HEIGHT + end + + lcd.drawText (X_COL2_HEADER+X_DATA_LEN/2,0, Title[1], TEXT_SIZE + INVERS + BOLD) + lcd.drawText (x_data,0, string.format("%2.2f",Values[1] or 0), TEXT_SIZE + INVERS+ RIGHT) + lcd.drawText (x_data+X_DATA_SPACE, 0, uom[1], TEXT_SIZE + INVERS) +end + + + + +local function openTelemetryRaw(i2cId) + --Init telemetry (Spectrun Telemetry Raw STR) + multiBuffer( 0, string.byte('S') ) + multiBuffer( 1, string.byte('T') ) + multiBuffer( 2, string.byte('R') ) + multiBuffer( 3, i2cId ) -- Monitor this teemetry data + multiBuffer( 4, 0 ) -- Allow to get Data +end + +local function closeTelemetryRaw() + multiBuffer(0, 0) -- Destroy the STR header + multiBuffer(3, 0) -- Not requesting any Telementry ID +end + +local lineText = {nil} +local I2C_TEXT_GEN = 0x0C +local function drawTextGen(event) + if (multiBuffer(0)~=string.byte('S')) then -- First time run??? + openTelemetryRaw(I2C_TEXT_GEN) -- I2C_ID for TEXT_GEN + lineText = {nil} + end + + -- Proces TEXT GEN Telementry message + if multiBuffer( 4 ) == I2C_TEXT_GEN then -- Specktrum Telemetry ID of data received + local instanceNo = multiBuffer( 5 ) + local lineNo = multiBuffer( 6 ) + + local line = "" + for i=0,13 do + line = line .. string.char(multiBuffer( 7 + i )) + end + + multiBuffer( 4, 0 ) -- Clear Semaphore, to notify that we fully process the current message + lineText[lineNo]=line + end + + lcd.clear() + -- Header + if (lineText[0]) then + lcd.drawText (X_COL1_HEADER,0, " "..lineText[0].." ", TEXT_SIZE + BOLD + INVERS) + else + lcd.drawText (X_COL1_HEADER,0, "TextGen", TEXT_SIZE+INVERS) + end + + -- Menu lines + local y = Y_DATA + for i=1,8 do + if (lineText[i]) then + lcd.drawText (X_COL1_HEADER,y, lineText[i], TEXT_SIZE) + end + y = y + Y_LINE_HEIGHT + end + + if event == EVT_VIRTUAL_EXIT then -- Exit?? Clear menu data + closeTelemetryRaw() + end +end + + +local telPage = 1 +local telPageSelected = 0 +local pageTitle = {[0]="Main", "AS3X Settings", "SAFE Settings", "ESC Status", "Battery Status","TextGen","Flight Log"} + +local function drawMainScreen(event) + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry (Smart RXs)", TEXT_SIZE + INVERS) + + for iParam=1,#pageTitle do + -- highlight selected parameter + local attr = (telPage==iParam) and INVERS or 0 + + -- set y draw coord + local y = (iParam)*Y_LINE_HEIGHT+Y_DATA + + -- labels + local x = X_COL1_HEADER + local val = pageTitle[iParam] + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + + if event == EVT_VIRTUAL_PREV then + if (telPage>1) then telPage = telPage - 1 end + elseif event == EVT_VIRTUAL_NEXT then + if (telPage<#pageTitle) then telPage = telPage + 1 end + elseif event == EVT_VIRTUAL_ENTER then + telPageSelected = telPage + end +end + + +local pageDraw = {[0]=drawMainScreen, drawAS3XSettingsP1, drawAS3XSettingsP2, drawESCStatus, drawBATStatus, drawTextGen, drawFlightLogScreen} + +local function run_func(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + -- draw specific page + pageDraw[telPageSelected](event) + + if event == EVT_VIRTUAL_EXIT then + if (telPageSelected==0) then return 1 end -- on Main?? Exit Script + telPageSelected = 0 -- any page, return to Main + end + + return 0 +end + +local function init_func() + + if (LCD_W <= 128 or LCD_H <=64) then -- Smaller Screens + TEXT_SIZE = SMLSIZE + X_COL1_HEADER = 0 + X_COL1_DATA = 20 + + X_COL2_HEADER = 60 + X_COL2_DATA = 90 + + X_DATA_LEN = 28 + X_DATA_SPACE = 1 + + + Y_LINE_HEIGHT = 8 + Y_DATA = Y_HEADER + Y_LINE_HEIGHT + + end +end + +return { run=run_func, init=init_func } diff --git a/SCRIPTS/TOOLS/Game-Breakout.lua b/SCRIPTS/TOOLS/Game-Breakout.lua new file mode 100755 index 0000000..7eac869 --- /dev/null +++ b/SCRIPTS/TOOLS/Game-Breakout.lua @@ -0,0 +1,508 @@ +-------------------------------------------------------- +-- BREAKOUT FOR X-LITE V2.0 +-------------------------------------------------------- +-- Basic script (c)2016 for Taranis by 'travir' +-- Rewritten and enhanced for the X-Lite +-- (c)2018 by Mike Dogan (mike-vom-mars.com) +-------------------------------------------------------- + +local screenWidth = math.floor( LCD_W ) +local screenHeight = math.floor( LCD_H ) + +local score = 0 +local lives = 5 +local level = 1 +local map = 1 +local bricks = {} +local brickWidth = 8 +local brickHeight = 6 +local brickGapWidth = 2 +local brickGapHeight = 2 +local visibleBricks = 0 + +local showSplash = getTime() +local playSplash = true +local showGameOver = 0 +local showLevelUp = 0 +local showStats = false +local playStats = false + +local paddle = {} +paddle.width = 24 +paddle.height = 4 +paddle.x = screenWidth / 2 - paddle.width / 2 +paddle.y = screenHeight - paddle.height +paddle.dx = 1 + +local ball = {} +ball.width = 4 +ball.height = 4 +ball.x = 0 +ball.y = 0 +ball.dx = 0 +ball.dy = 0 +local lx = ball.x +local ly = ball.y + +local oldTime + +local stats = + { + begin = 0, + finish = 0, + kills = 0, + score = 0, + level = 0, + } + +local maps = + { + { + 1,1,1,1,1,0,0,1,1,1,1,1, + 1,1,1,1,1,0,0,1,1,1,1,1, + 1,1,1,1,1,0,0,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 1,0,1,0,1,0,1,0,1,0,1,0, + 0,1,0,1,0,1,0,1,0,1,0,1, + 1,0,1,0,1,0,1,0,1,0,1,0, + 0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 2,2,2,2,2,0,0,2,2,2,2,2, + 2,2,2,2,2,0,0,2,2,2,2,2, + 1,1,1,1,1,0,0,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 2,2,2,0,2,0,2,0,0,2,2,2, + 2,1,2,0,2,0,2,0,0,2,1,2, + 2,1,2,0,2,0,2,0,0,2,1,2, + 2,2,2,0,2,0,2,0,0,2,2,2, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 3,3,3,3,3,0,0,3,3,3,3,3, + 2,2,2,2,2,0,0,2,2,2,2,2, + 2,2,2,2,2,0,0,2,2,2,2,2, + 3,3,3,3,3,0,0,3,3,3,3,3, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 1,2,3,1,2,3,1,2,3,1,2,3, + 2,3,1,2,3,1,2,3,1,2,3,1, + 3,1,2,3,1,2,3,1,2,3,1,2, + 1,2,3,1,2,3,1,2,3,1,2,3, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 3,1,3,1,3,1,1,3,1,3,1,3, + 3,1,3,1,3,1,1,3,1,3,1,3, + 3,1,3,1,3,1,1,3,1,3,1,3, + 3,1,3,1,3,1,1,3,1,3,1,3, + 0,0,0,0,0,0,0,0,0,0,0,0, + }, + { + 0,3,2,3,2,3,3,2,3,2,3,0, + 0,0,3,2,3,2,2,3,2,3,0,0, + 0,0,0,3,2,3,3,2,3,0,0,0, + 0,0,0,0,3,2,2,3,0,0,0,0, + 0,0,0,0,0,3,3,0,0,0,0,0, + }, + { + 3,2,0,3,2,0,3,2,0,3,2,0, + 3,2,0,3,2,0,3,2,0,3,2,0, + 3,2,0,3,2,0,3,2,0,3,2,0, + 3,2,0,3,2,0,3,2,0,3,2,0, + 3,2,0,3,2,0,3,2,0,3,2,0, + }, + { + 1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3, + }, + { + 3,3,3,0,3,3,3,3,0,3,3,3, + 3,2,3,0,0,0,0,0,0,3,2,3, + 3,3,3,0,3,3,3,3,0,3,3,3, + 0,0,0,0,3,2,2,3,0,0,0,0, + 3,3,3,0,3,3,3,3,0,3,3,3, + }, + { + 3,3,3,3,3,3,3,3,3,3,3,3, + 3,1,1,1,1,1,1,1,1,1,1,1, + 3,3,3,3,3,3,3,3,3,3,3,3, + 1,1,1,1,1,1,1,1,1,1,1,3, + 3,3,3,3,3,3,3,3,3,3,3,3, + }, + { + 3,3,3,1,3,3,3,1,3,3,3,1, + 3,1,3,1,3,1,3,1,3,1,3,1, + 3,1,3,1,3,1,3,1,3,1,3,1, + 3,1,3,1,3,1,3,1,3,1,3,1, + 3,1,3,3,3,1,3,3,3,1,3,3, + }, + } + + +--------------------------------------- + +local function createBricks() + local k + local i = 1 + local col = 1 + local row = 1 + visibleBricks = 0 + + for k in pairs (bricks) do bricks[k] = nil end + bricks = {} + + for row = 1,5 do + for col = 1,12 do + local p = (row-1)*12 + col + if maps[map][p] > 0 then + bricks[i] = {} + bricks[i].x = 5 + (col-1) * (brickWidth +brickGapWidth) + bricks[i].y = 9 + (row-1) * (brickHeight+brickGapHeight) + bricks[i].lives = maps[map][p] + i = i + 1 + visibleBricks = visibleBricks + 1 + end + end + end +end + +--------------------------------------- + +local function resetBall() + ball.dx = 0 + ball.dy = 0 +end + +--------------------------------------- + +local function reset(won) + -- NEW GAME? + if won == nil then + stats.begin = getTime() + stats.score = 0 + stats.kills = 0 + stats.level = 1 + -- GAME OVER? + elseif won == false then + stats.level = level + stats.finish = getTime() + showGameOver = getTime() + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/gover.wav") + end + + -- RESET VARS + lives = won == true and lives or 5 + score = won == true and score or 0 + level = won == true and level + 1 or 1 + map = won == true and map + 1 or 1; if map > #maps then map = 1 end + -- PLACE PADDLE + paddle.x = screenWidth / 2 - paddle.width / 2 + paddle.y = screenHeight - paddle.height + + resetBall() + createBricks() +end + +--------------------------------------- + +local function drawAll() + -- BRICKS + for i, brick in pairs(bricks) do + if brick.lives == 1 then + lcd.drawRectangle(brick.x, brick.y, brickWidth, brickHeight) + elseif brick.lives == 2 then + lcd.drawRectangle(brick.x, brick.y, brickWidth, brickHeight) + lcd.drawFilledRectangle(brick.x+2, brick.y+2, brickWidth-4, brickHeight-4, 0) + elseif brick.lives == 3 then + lcd.drawFilledRectangle(brick.x, brick.y, brickWidth, brickHeight, 0) + end + end + -- BALL & BAT + lcd.drawRectangle(paddle.x, paddle.y, paddle.width, paddle.height, 0) + lcd.drawFilledRectangle(paddle.x+3, paddle.y+1, paddle.width-6, paddle.height-2, 0) + lcd.drawFilledRectangle(ball.x, ball.y, ball.width, ball.height, 0) + -- TEXTS + if ball.dx == 0 and ball.dy == 0 then + lcd.drawText(7, 1, " PULL STICK UP! ", SMLSIZE + INVERS + BLINK) + else + --lcd.drawText(100, 0, visibleBricks, 0) + lcd.drawText(5, 1, "LIVES: " .. lives, SMLSIZE + (lives == 0 and BLINK or 0) ) + lcd.drawText(55, 1, "SCORE: " .. score, SMLSIZE) + end +end + +--------------------------------------- + +local function collisionDetection(aX, aY, aW, aH, bX, bY, bW, bH) + if aY + aH < bY then + return false + elseif aY > bY + bH then + return false + elseif aX + aW < bX then + return false + elseif aX > bX + bW then + return false + else + return true; + end +end + +--------------------------------------- + +local function update(deltaTime) + if collisionDetection(ball.x, ball.y, ball.width, ball.height, + paddle.x, paddle.y, paddle.width, paddle.height) then + + -- RANDOMIZE A BIT + local xr = math.random(90,110)/100 + local yr = math.random(90,110)/100 + + if ball.y > paddle.y - paddle.height then + ball.y = ball.y + paddle.y - ball.y - ball.height + end + + if ball.dx > 0 then -- BALL MOVING TO RIGHT? + if ball.x < paddle.x + ball.width then + ball.dx = -ball.dx * xr + end + elseif ball.dx < 0 then -- BALL MOVING TO LEFT? + if ball.x > paddle.x + paddle.width - ball.width then + ball.dx = -ball.dx * xr + end + end + + ball.dy = -ball.dy * yr + + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/bat.wav") + end + + for i, brick in pairs(bricks) do + if brick.lives > 0 then + if collisionDetection(ball.x, ball.y, ball.width, ball.height, + brick.x, brick.y, brickWidth, brickHeight) then + + if ball.y < brick.y + brickHeight then -- Hit was below the brick + ball.dy = -ball.dy + elseif ball.y + ball.height > brick.y then -- Hit was above the brick + ball.dy = -ball.dy + end + + if ball.x < brick.x + brickWidth then -- Brick hit on right + ball.dx = -ball.dx + elseif ball.x + ball.width > brick.x then -- Brick hit on left + ball.dx = -ball.dx + end + + ball.x = lx + ball.y = ly + + brick.lives = brick.lives - 1 + if brick.lives == 0 then + stats.kills = stats.kills + 1 + visibleBricks = visibleBricks - 1 + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/brick.wav") + else + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/brick.wav") + end + score = score + 10; stats.score = score + if visibleBricks == 0 then + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/up.wav") + reset(true) + showLevelUp = getTime() + end + end + end + end + + + -- BALL STICKS TO BAT? + if ball.dx == 0 and ball.dy == 0 then + ball.x = paddle.x + paddle.width/2 + ball.y = paddle.y - paddle.height - 2 + -- THROW BALL! + if getValue("ele") > 500 then + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/throw.wav") + ball.dx = math.random(1,2) == 1 and -0.55 or 0.55 + ball.dy = -0.5 + print(getValue("thr")) + end + -- BALL IS MOVING + else + lx = ball.x + ly = ball.y + ball.x = ball.x + ball.dx * deltaTime + ball.y = ball.y + ball.dy * deltaTime + end + + if getValue('ail') > 150 or getValue('rud') > 150 then + paddle.x = paddle.x + paddle.dx * deltaTime + end + if getValue('ail') < -150 or getValue('rud') < -150 then + paddle.x = paddle.x - paddle.dx * deltaTime + end + + --if getValue('ele') > 999 or getValue('ele') < -999 then + -- playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/up.wav") + -- reset(true) + -- showLevelUp = getTime() + --end + + if ball.x + ball.width > screenWidth then + ball.x = screenWidth - ball.width + ball.dx = -ball.dx + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/border.wav") + elseif ball.x < 0 then + ball.x = 0 + ball.dx = -ball.dx + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/border.wav") + end + + if ball.y < 0 then + ball.y = 0 + ball.dy = -ball.dy + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/border.wav") + -- LOST BALL? + elseif ball.y + ball.height > screenHeight then + resetBall() + lives = lives - 1 + + if lives >= 0 then + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/killed.wav") + elseif lives < 0 then + reset(false) + end + end + + if paddle.x + paddle.width > screenWidth then + paddle.x = screenWidth - paddle.width + elseif paddle.x < 0 then + paddle.x = 0 + end +end + +--------------------------------------- + +function secsToClock(seconds) + local seconds = tonumber(seconds) + + if seconds <= 0 then + return "00:00:00"; + else + hours = string.format("%02.f", math.floor(seconds/3600)); + mins = string.format("%02.f", math.floor(seconds/60 - (hours*60))); + secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60)); + return hours..":"..mins..":"..secs + end +end + +--------------------------------------- + +local function init() + -- lcd.lock() + lcd.clear() + createBricks() + reset() + drawAll() + oldTime = getTime() + +end + +--------------------------------------- + +local function run(event) + if event == EVT_EXIT_BREAK then return 2 end + + local newTime = getTime() + local deltaTime = newTime - oldTime + lcd.clear() + + -- SPLASH SCREEN + if showSplash > 0 then + if newTime < (showSplash+250) then + if playSplash == true then + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/splash.wav") + playSplash = false + end + lcd.drawPixmap(0,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/splash1.bmp") + lcd.drawPixmap(64,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/splash2.bmp") + return 0 + else + showSplash = 0 + end + + -- GAME OVER SCREEN + elseif showGameOver > 0 then + if newTime < (showGameOver+350) then + lcd.drawPixmap(0,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/gover1.bmp") + lcd.drawPixmap(64,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/gover2.bmp") + return 0 + else + showGameOver = 0 + showStats = true + playStats = true + return 0 + end + + -- SHOW STATS SCREEN + elseif showStats == true then + if playStats == true then + playFile("/SCRIPTS/TOOLS/BREAKOUT/snd/stats.wav") + playStats = false + end + lcd.drawRectangle(2, 2, screenWidth-4, screenHeight-4) + lcd.drawText(5,6, "Level:", 0) + lcd.drawText(5,16, "Your score:", 0) + lcd.drawText(5,26, "Time played:", 0) + lcd.drawText(5,36, "Bricks killed:", 0) + lcd.drawText(85,6, stats.level, 0) + lcd.drawText(85,16, stats.score, 0) + lcd.drawText(85,26, secsToClock( (stats.finish-stats.begin)/100 ), 0) + lcd.drawText(85,36, stats.kills, 0) + lcd.drawText(6,51, "-STICK UP TO CONTINUE-", INVERS) + -- DISMISS? + if getValue("ele") > 500 then + showStats = false + -- SPLASH SCREEN + showSplash = getTime() + playSplash = true + return 0 + end + + -- LEVEL UP SCREEN + elseif showLevelUp > 0 then + if newTime < (showLevelUp+250) then + lcd.drawPixmap(0,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/up1.bmp") + lcd.drawPixmap(64,0, "/SCRIPTS/TOOLS/BREAKOUT/gfx/up2.bmp") + return 0 + else + showLevelUp = 0 + end + + -- GAME RUNNING + else + update(deltaTime) + drawAll() + end + -- lcd.lock() + + oldTime = newTime + + + + return 0 +end + + +return {init=init, run=run} diff --git a/SCRIPTS/TOOLS/Game-Breakout.luac b/SCRIPTS/TOOLS/Game-Breakout.luac new file mode 100755 index 0000000..aa0dc92 Binary files /dev/null and b/SCRIPTS/TOOLS/Game-Breakout.luac differ diff --git a/SCRIPTS/TOOLS/Graupner HoTT Model Locator.lua b/SCRIPTS/TOOLS/Graupner HoTT Model Locator.lua new file mode 100644 index 0000000..32c8116 --- /dev/null +++ b/SCRIPTS/TOOLS/Graupner HoTT Model Locator.lua @@ -0,0 +1,167 @@ +---- ######################################################################### +---- # # +---- # Telemetry Widget script for FrSky Horus/Radio Master TX16s # +---- # 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. # +---- # # +---- ######################################################################### + +-- Model Locator by RSSI +-- Offer Shmuely (based on code from Scott Bauer 6/21/2015) +-- Date: 2021 +-- ver: 0.1 + +-- MHA (based on code from Offer Shmuely) +-- Date: 2022 +-- ver: 0.11 +-- changes: made version for Graupner HoTT. Uses real Rssi data scaled -15db to -115db to 100..0 + +-- This widget help to find a lost/crashed model based on the RSSI (if still available) +-- The widget produce audio representation (variometer style) of the RSSI from the lost model +-- The widget also display the RSSI in a visible colorized bar (0-100%) + +-- There are two way to use it +-- 1. The simple way: +-- walk toward the quad/plane that crashed, +-- as you get closer to your model the beeps will become more frequent with higher pitch (and a visual bar graph as well) +-- until you get close enough to find it visually + +-- 2. the more accurate way: +-- turn the antenna straight away (i.e. to point from you, straight away) +-- try to find the weakest signal! (not the highest), i.e. the lowest RSSI you can find, this is the direction to the model. +-- now walk to the side (not toward the model), find again the weakest signal, this is also the direction to your model +-- triangulate the two lines, and it will be :-) + +local delayMillis = 100 +local nextPlayTime = getTime() +local img = Bitmap.open("/SCRIPTS/TOOLS/Model Locator (by RSSI).png") + +-------------------------------------------------------------- +local function log(s) + --return; + print("locator: " .. s) +end +-------------------------------------------------------------- + + +-- init_func is called once when model is loaded +local function init() + return 0 +end + +-- bg_func is called periodically when screen is not visible +local function bg() + return 0 +end + +-- This function returns green at gvalue, red at rvalue and graduate in between +local function getRangeColor(value, red_value, green_value) + local range = math.abs(green_value - red_value) + if range == 0 then + return lcd.RGB(0, 0xdf, 0) + end + if value == nil then + return lcd.RGB(0, 0xdf, 0) + end + + if green_value > red_value then + if value > green_value then + return lcd.RGB(0, 0xdf, 0) + end + if value < red_value then + return lcd.RGB(0xdf, 0, 0) + end + g = math.floor(0xdf * (value - red_value) / range) + r = 0xdf - g + return lcd.RGB(r, g, 0) + else + if value > green_value then + return lcd.RGB(0, 0xdf, 0) + end + if value < red_value then + return lcd.RGB(0xdf, 0, 0) + end + r = math.floor(0xdf * (value - green_value) / range) + g = 0xdf - r + return lcd.RGB(r, g, 0) + end +end + +local function main(event) + + lcd.clear() + + -- fetch uplink rssi (HoTT sensor Rssi) + local rssi = getValue("Rssi") + + -- calculate a percentage for the color bar (range -115db to -15db) + local rssiP = rssi + + if(rssi ~= 0) then -- rssi < 0 -> telemtry data received + if(rssi >= -15) then -- -15db to -1db => 100% + rssiP = 100 + else + if(rssi >= -115) then -- between -115db and -15db => 0% to 100% + rssiP = 100+rssi+15 + else + rssiP = 0 -- less than -115 => 0% + end + end + end + + lcd.drawBitmap(img, 250, 50, 40) + + -- Title + lcd.drawText(3, 3, "Graupner HoTT Rssi Model Locator", 0) + myColor = getRangeColor(rssi, 0, 100) + lcd.setColor(CUSTOM_COLOR, myColor) + + -- draw current value + local dx = 0 + if rssi < -99 then + dx = -33 + end + + if rssi == 0 then + lcd.drawText(115, 73, "no telemetry", DBLSIZE + CUSTOM_COLOR) + else + lcd.drawNumber(180+dx, 30, rssi, XXLSIZE + CUSTOM_COLOR) + lcd.drawText(275, 73, "db", 0 + CUSTOM_COLOR) + end + + -- draw main bar + lcd.setColor(CUSTOM_COLOR, YELLOW) -- RED / YELLOW + local xMin = 0 + local yMin = 270 + local xMax = 480 + local yMax = 200 + local h = 0 + local rssiAsX = (rssiP * xMax) / 100 + + for xx = xMin, rssiAsX, 20 do + lcd.setColor(CUSTOM_COLOR, getRangeColor(xx, xMin, xMax - 40)) + h = h + 10 + lcd.drawFilledRectangle(xx, yMin - h, 15, h, CUSTOM_COLOR) + end + + -- beep + if getTime() >= nextPlayTime then + playFile("/SCRIPTS/TOOLS/Model Locator (by RSSI).wav") + nextPlayTime = getTime() + delayMillis - rssiP + end + + return 0 +end + +return {init = init,run = main,background = bg} + diff --git a/SCRIPTS/TOOLS/Graupner HoTT.lua b/SCRIPTS/TOOLS/Graupner HoTT.lua new file mode 100644 index 0000000..d0a7d4a --- /dev/null +++ b/SCRIPTS/TOOLS/Graupner HoTT.lua @@ -0,0 +1,171 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### + + +--############################################################################### +-- Multi buffer for HoTT description +-- To start operation: +-- Write "HoTT" at address 0..3 +-- Write 0xFF at address 4 will request the buffer to be cleared +-- Write 0x0F at address 5 +-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters +-- by 8 lines +-- Write at address 5 sends an order to the RX: 0xXF=start, 0xX7=prev page, +-- 0xXE=next page, 0xX9=enter, 0xXD=next or 0xXB=prev with X being the sensor +-- to request data from 8=RX only, 9=Vario, A=GPS, B=Cust, C=ESC, D=GAM, E=EAM +-- Write at address 4 the value 0xFF will request the buffer to be cleared +-- !! Before exiting the script must write 0 at address 0 for normal operation !! +--############################################################################### + +HoTT_Sensor = 0 +Timer_128 = 100 + +local function HoTT_Release() + multiBuffer( 0, 0 ) +end + +local function HoTT_Send(button) + multiBuffer( 5, 0x80+(HoTT_Sensor*16) + button) +end + +local function HoTT_Sensor_Inc() + local detected_sensors=multiBuffer( 4 ) + local a + if detected_sensors ~= 0xFF then + repeat + HoTT_Sensor=(HoTT_Sensor+1)%7 -- Switch to next sensor + if HoTT_Sensor ~= 0 then + a = math.floor(detected_sensors/ (2^(HoTT_Sensor-1))) -- shift right + end + until HoTT_Sensor==0 or a % 2 == 1 + HoTT_Send( 0x0F ) + end +end + +local function HoTT_Draw_LCD() + local i + local value + local line + local result + local offset=0 + + local sensor_name = { "", "+Vario", "+GPS", "+Cust", "+ESC", "+GAM", "+EAM" } + + lcd.clear() + + if LCD_W == 480 then + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, "Graupner HoTT: config RX" .. sensor_name[HoTT_Sensor+1] .. " - Menu cycle Sensors", MENU_TITLE_COLOR) + --Draw RX Menu + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(10,50,"No HoTT telemetry...", BLINK) + else + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(10+i*16,32+20*line,string.char(value).." ",INVERS) + else + lcd.drawText(10+i*16,32+20*line,string.char(value)) + end + end + end + end + else + --Draw RX Menu on LCD_W=128 + if multiBuffer( 4 ) == 0xFF then + lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE) + else + if Timer_128 ~= 0 then + --Intro page + Timer_128 = Timer_128 - 1 + lcd.drawScreenTitle("Graupner Hott",0,0) + lcd.drawText(2,17,"Configuration of RX" .. sensor_name[HoTT_Sensor+1] ,SMLSIZE) + lcd.drawText(2,37,"Press menu to cycle Sensors" ,SMLSIZE) + else + --Menu page + for line = 0, 7, 1 do + for i = 0, 21-1, 1 do + value=multiBuffer( line*21+6+i ) + if value > 0x80 then + value = value - 0x80 + lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS) + else + lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE) + end + end + end + end + end + end +end + +-- Init +local function HoTT_Init() + --Set protocol to talk to + multiBuffer( 0, string.byte('H') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('H') then + error("Not enough memory!") + return 2 + end + multiBuffer( 1, string.byte('o') ) + multiBuffer( 2, string.byte('T') ) + multiBuffer( 3, string.byte('T') ) + --Request init of the RX buffer + multiBuffer( 4, 0xFF ) + --Request RX to send the config menu + HoTT_Send( 0x0F ) + HoTT_Sensor = 0; + HoTT_Detected_Sensors=0; + Timer_128 = 100 +end + +-- Main +local function HoTT_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + HoTT_Release() + return 2 + else + if event == EVT_VIRTUAL_PREV_PAGE then + killEvents(event) + HoTT_Send( 0x07 ) + elseif event == EVT_VIRTUAL_ENTER then + HoTT_Send( 0x09 ) + elseif event == EVT_VIRTUAL_PREV then + HoTT_Send( 0x0B ) + elseif event == EVT_VIRTUAL_NEXT then + HoTT_Send( 0x0D ) + elseif event == EVT_VIRTUAL_NEXT_PAGE then + HoTT_Send( 0x0E ) + elseif event == EVT_VIRTUAL_MENU then + Timer_128 = 100 + HoTT_Sensor_Inc() + else + HoTT_Send( 0x0F ) + end + HoTT_Draw_LCD() + return 0 + end +end + +return { init=HoTT_Init, run=HoTT_Run } diff --git a/SCRIPTS/TOOLS/ModelLocator.lua b/SCRIPTS/TOOLS/ModelLocator.lua new file mode 100755 index 0000000..c22a200 --- /dev/null +++ b/SCRIPTS/TOOLS/ModelLocator.lua @@ -0,0 +1,157 @@ +---- TNS|Model Locator|TNE +---- ######################################################################### +---- # # +---- # Telemetry Widget script for b&w 128x64 radios # +---- # 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. # +---- # # +---- ######################################################################### + +-- Model Locator by RSSI +-- AegisCrusader & Offer Shmuely (based on code from Scott Bauer 6/21/2015) +-- Date: 2022-2024 +-- ver: 0.6 +local app_ver = "0.6" + +-- This widget help to find a lost/crashed model based on the RSSI (if still available) +-- The widget produce audio representation (vario-meter style) of the RSSI from the lost model +-- The widget also displays the RSSI in a visible bar + +-- There are two way to use it +-- 1. The simple way: +-- walk toward the quad/plane that crashed, +-- as you get closer to your model the beeps will become more frequent with higher pitch (and a visual bar graph as well) +-- until you get close enough to find it visually + +-- 2. the more accurate way: +-- turn the antenna straight away (i.e. to point from you, straight away) +-- try to find the weakest signal! (not the highest), i.e. the lowest RSSI you can find, this is the direction to the model. +-- now walk to the side (not toward the model), find again the weakest signal, this is also the direction to your model +-- triangulate the two lines, and it will be :-) + +local delayMillis = 100 +local targetTXPower = 25 +local nextPlayTime = getTime() +local useHaptic = false + +local function getSignalValues() + -- try to get transmitter power + local txPowerField = getFieldInfo("TPWR") + local txPowerValue = nil + if txPowerField then + txPowerValue = getValue("TPWR") + end + + -- try regular Frsky RSSI + local fieldinfo = getFieldInfo("RSSI") + if fieldinfo then + local v = getValue("RSSI") + return v, 0, 100, txPowerValue, "Using signal: Frsky RSSI", nil + end + + -- try expressLRS antenna 1 + local fieldinfo = getFieldInfo("1RSS") + if fieldinfo then + local v = getValue("1RSS") + if v == 0 then + v = -115 + end + return v, -115, 20, txPowerValue, "Using signal: ELRS 1RSS", "Set TX PWR 25mW No Dyn" + end + + -- try expressLRS antenna 2 + local fieldinfo = getFieldInfo("2RSS") + if fieldinfo then + local v = getValue("2RSS") + if v == 0 then + v = -115 + end + return v, -115, 20, txPowerValue, "Using signal: ELRS 2RSS", "Set TX PWR 25mW No Dyn" + end + + return nil, 0, 0 +end + +local function init() + lcd.clear() +end + +local function run(event) + -- exit script + if event == EVT_VIRTUAL_EXIT then + return 2 + end + + lcd.clear() + + local signalValue, signalMin, signalMax, txPower, line1, line2 = getSignalValues() + + lcd.drawText(0, 0, "Model Locator by RSSI", BOLD) + + if signalValue == nil then + lcd.drawText(0, 24, "No signal, expected:", 0 + BLINK) + lcd.drawText(0, 32, "RSSI/1RSS/2RSS", 0 + BLINK) + return 0 + end + + if txPower then + lcd.drawText(0, 16, "Current TX PWR: " .. tostring(txPower) .. "mW") + + if txPower ~= targetTXPower then + lcd.drawText(0, 8, line2 or "", BLINK) + else + lcd.drawText(0, 8, "[ENTER] to toggle haptic") + end + else + lcd.drawText(0, 8, "[ENTER] to toggle haptic") + end + + local signalPercent = 100 * ((signalValue - signalMin) / (signalMax - signalMin)) + + lcd.drawText(0, 24, tostring(signalValue) .. "dB", DBLSIZE) + + -- draw main bar + local xMin = 10 + local yMin = LCD_H - 10 + local xMax = LCD_W + local h = 0 + local rssiAsX = (signalPercent * xMax) / 100 + + for xx = xMin, rssiAsX, 7 do + h = h + 2 + lcd.drawFilledRectangle(xx, yMin - h, 5, h) + end + + lcd.drawFilledRectangle(0, LCD_H - 10, LCD_W, 1) + + -- current signal type + lcd.drawText(0, LCD_H - 8, line1) + + -- toggle haptic + if event == EVT_VIRTUAL_ENTER then + useHaptic = not useHaptic + end + + -- beep + if getTime() >= nextPlayTime then + playFile("/SCRIPTS/TOOLS/modloc.wav") + if useHaptic then + playHaptic(7, 0, 1) + end + nextPlayTime = getTime() + delayMillis - signalPercent + end + + return 0 +end + +return {init = init, run = run} diff --git a/SCRIPTS/TOOLS/ModelLocator.luac b/SCRIPTS/TOOLS/ModelLocator.luac new file mode 100755 index 0000000..aa0ca2c Binary files /dev/null and b/SCRIPTS/TOOLS/ModelLocator.luac differ diff --git a/SCRIPTS/TOOLS/MultiChan.txt b/SCRIPTS/TOOLS/MultiChan.txt new file mode 100644 index 0000000..402b7de --- /dev/null +++ b/SCRIPTS/TOOLS/MultiChan.txt @@ -0,0 +1,233 @@ +24,0,Assan,Std,0,CH5,CH6,CH7,CH8 +14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2 +14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates +14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf +14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop +14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop +14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop +59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video +59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video +41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED +42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED +42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol +34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess +13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess +37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8 +37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8 +37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8 +12,0,CX10,Green,1,Flip,Rate +12,1,CX10,Blue,1,Flip,Rate,Pict,Video +12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess +12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video +12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip +12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH +7,0,Devo,8CH,0,CH5,CH6,CH7,CH8 +7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10 +7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +7,3,Devo,6CH,0,CH5,CH6 +7,4,Devo,7CH,0,CH5,CH6,CH7 +33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow +6,0,DSM,2_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill +6,1,DSM,2_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill +6,2,DSM,X_1F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill +6,3,DSM,X_2F,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill +6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill +6,5,DSM,R_1F,0,AUX3,AUX4,AUX5 +6,6,DSM,2SFC,0 +70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH +45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH +16,0,ESKY,Std,0,Gyro,Pitch +16,1,ESKY,ET4,0,Gyro,Pitch +35,0,ESKY150,4CH,0 +35,1,ESKY150,7CH,0,FMode,Aux6,Aux7 +69,0,ESKY150V2,Std,0,CH5_RA,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8 +1,1,Flysky,V9x9,1,Flip,Light,Pict,Video +1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL +1,3,Flysky,V912,1,BtmBtn,TopBtn +1,4,Flysky,CX20,0,CH5,CH6,CH7 +28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +28,6,Flysky_AFHDS2A,PWM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +28,7,Flysky_AFHDS2A,PPM_SB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +53,0,Height,5ch,0,Gear +53,1,Height,8ch,0,Gear,Gyro,Flap,Light +25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8 +3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8 +3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8 +67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +67,1,FrSkyL,LR12_6CH,0,CH5,CH6 +15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8 +15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8 +15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +15,5,FrSkyX,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8 +64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8 +64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +64,5,FrSkyX2,D16Cloned_8CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8 +65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8 +55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +55,1,FrSkyRX,CloneTX,0 +55,2,FrSkyRX,EraseTX,0 +55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +58,0,FX,816,1 +58,1,FX,620,1 +58,2,FX,9630,1,Rate,Gyro,TrimR,TrimA,TrimE +58,3,FX,Q560,1,FLIP,Gyro,LEDs +20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib +20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib +23,0,FY326,FY326,1,Flip,RTH,HLess,Expert +47,0,GD00x,V1,1,Trim,LED,Rate +47,1,GD00x,V2,1,Trim,LED,Rate +32,0,GW008,FY326,1,Flip +36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1 +36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal +36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal +36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal +4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8 +4,1,Hisky,HK310,0,Aux +39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9 +39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9 +39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9 +26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib +26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib +26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib +26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib +26,4,Hontai,XKK170,1,Rate,Emerg,TakLan,Calib,TrimA,TrimE +57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess +2,1,Hubsan,H301,0,RTH,Light,Stab,Video +2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes +22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12 +71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3 +71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3 +49,0,KF606,KF606,1,Trim +49,1,KF606,MIG320,1,Trim,LED +49,2,KF606,ZCZ50,1,Trim,UNK +9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover +9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim,Rtrim,Hover +73,0,Kyosho,FHSS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 +73,1,Kyosho,Hype,0,CH5,CH6 +18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate +17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess +17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess +17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess +17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess +17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess +17,5,MT99XX,A180,0,3D_6G +17,6,MT99XX,Dragon,0,Mode,RTH +17,7,MT99XX,F949G,0,6G_3D,Light +44,0,NCC1701,Std,1,Warp +77,0,OMP,M2,0,THold,IdleUp,6G_3D +60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8 +60,1,Pelikan,LITE_V4,0,CH5,CH6,CH7,CH8 +60,2,Pelikan,SCX24,0 +51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess +66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train +29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal +29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal +31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal +31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal +31,2,Q303,CX10D,1,Arm,Flip +31,3,Q303,CX10WD,1,Arm,Flip +72,0,Q90C,Std,0,FMode,VTX+ +74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8 +74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8 +74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8 +74,3,RadioLink,RC4G,0,CH5,FS_CH1,FS_CH2,FS_CH3,FS_CH4 +76,0,Realacc,Std,1,Flip,Light,Calib,HLess,RTH,ThCut,Rotat +50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16 +50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16 +21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8 +19,0,Shenqi,Cycle,1 +68,0,Skyartec,Std,0,CH5,CH6,CH7 +11,0,SLT,V1,0,Gear,Pitch +11,1,SLT,V2,0,CH5,CH6,CH7,CH8 +11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib +11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib +11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict +11,5,SLT,V1_4CH,0 +11,6,SLT,RF_SIM,0,CH5,CH6,CH7,CH8,CH9,CH10 +10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess +10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess +43,0,Traxxas,TQ2,0 +43,1,Traxxas,TQ1,0 +5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY +5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD +48,0,V761,3CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep +48,1,V761,4CH,0,Gyro,Calib,Flip,RtnAct,Rtn,Beep +48,2,V761,TOPRC,0,Gyro,Calib,Flip,RtnAct,Rtn +46,0,V911s,V911s,1,Calib,Rate +46,1,V911s,E119,1,Calib,Rate,6G_3D +22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9 +30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8 +30,1,WK2x01,WK2401,0 +30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro +30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro +30,4,WK2x01,W6HEL,0,Gear,Col,Gyro +30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro +62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video +62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light +62,2,XK,Cars,0,FMode,TakeOf,Emerg,3D_6G,Pict,Video,Flip,Light +99,0,XK2,X4,0,Rate,Mode,Hover,Light +99,1,XK2,P10,0,Rate,Mode,Hover,Light +8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess +8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess +8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess +8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess +8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess +52,0,ZSX,280,1,Light +78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16 +79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10 +80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH +81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE +82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe +83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR +83,1,E129,C186,1,TakLan,EmStop,TrimA,TrimE,TrimR,Loop,Flip,Debug +84,0,JOYSWAY,Std,0 +85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH +87,0,IKEA +89,0,LOSI +90,0,MouldKg,Analog,0 +90,1,MouldKg,Digit,0 +91,0,Xerall,Tank,0,FlTa,TakLan,Rate,HLess,Photo,Video,TrimR,TrimE,TrimA +92,0,MT99xx2,PA18,0,MODE,FLIP,RTH +92,1,MT99xx2,SU35,0,Mode,LED,LED_FH,Invert,Rate +93,0,Kyosho2,KT-17,0 +94,0,Scorpio +95,0,Bluefly,HP100,0,CH5,CH6,CH7,CH8 +96,0,BumbleB +97,0,SGF22,F22,1,Mode,Flip,LED,Pict,Video,TrRes,Bal,HiBal +97,1,SGF22,F22S,1,Mode,Flip,LED,Pict,Video,TrRes +97,2,SGF22,J20,1,Mode,Flip,LED,Pict,Video +61,0,EazyRC +98,0,Kyosho3,ASF,0 +100,0,YuXiang,Std,0,Lock,Rate,Land,Manual,Flip,Mode,Pitch +102,0,JIABAILE,Std,0,Speed,Light,Flash +102,1,JIABAILE,Gyro,0,Speed,Light,Flash,Tr_ST +103,0,H36,Std,1,Flip,HLess,RTH diff --git a/SCRIPTS/TOOLS/MultiChannelsUpdater.lua b/SCRIPTS/TOOLS/MultiChannelsUpdater.lua new file mode 100644 index 0000000..a905cd8 --- /dev/null +++ b/SCRIPTS/TOOLS/MultiChannelsUpdater.lua @@ -0,0 +1,327 @@ + +local toolName = "TNS|Multi chan namer|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 protocol_name = "" +local sub_protocol_name = "" +local bind_ch = 0 +local module_conf = {} +local module_pos = "Internal" +local file_ok = 0 +local done = 0 +local protocol = 0 +local sub_protocol = 0 +local f_seek = 0 +local channel_names={} +local num_search = "Searching" + +local function drawScreenTitle(title) + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, 0, 0) + end +end + +function bitand(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits + result = result + bitval -- set the current bit + end + bitval = bitval * 2 -- shift left + a = math.floor(a/2) -- shift right + b = math.floor(b/2) + end + return result +end + +local function Multi_Draw_LCD(event) + local line = 0 + + lcd.clear() + drawScreenTitle("Multi channels namer") + + --Display settings + local lcd_opt = 0 + if LCD_W == 480 then + x_pos = 10 + y_pos = 32 + y_inc = 20 + else + x_pos = 0 + y_pos = 9 + y_inc = 8 + lcd_opt = SMLSIZE + end + + --Multi Module detection + if module_conf["Type"] ~= 6 then + if LCD_W == 480 then + lcd.drawText(10,50,"No Multi module configured...", BLINK) + else + --Draw on LCD_W=128 + lcd.drawText(2,17,"No Multi module configured...",SMLSIZE) + end + return + else + lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt) + line = line + 1 + end + + --Channel order + if (ch_order == -1) then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt) + line = line + 1 + end + + --Can't open file MultiChan.txt + if file_ok == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt) + return + end + + if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt) + num_search = num_search .. "." + if #num_search > 15 then + num_search = string.sub(num_search,1,9) + end + local proto = 0 + local sub_proto = 0 + local proto_name = "" + local sub_proto_name = "" + local channels = "" + local nbr_try = 0 + local nbr_car = 0 + repeat + io.seek(f, f_seek) + local data = io.read(f, 100) -- read 100 characters + if #data ==0 then + f_seek = -1 -- end of file + break + end + proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)') + if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then + if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then + protocol_name = proto_name + sub_protocol_name = sub_proto_name + bind_ch = tonumber(bind_ch) + if channels ~= nil then + --extract channel names + nbr_car = string.find(channels, "\r") + if nbr_car == nil then nbr_car = string.find(channels, "\n") end + if nbr_car ~= nil then + channels = string.sub(channels,1,nbr_car-1) + end + local i = 5 + for k in string.gmatch(channels, ",([%w-_ ]+)") do + channel_names[i] = k + i = i + 1 + end + end + f_seek = -1 -- protocol found + break + end + end + if f_seek ~= -1 then + nbr_car = string.find(data, "\n") + if nbr_car == nil then nbr_car = string.find(data, "\r") end + if nbr_car == nil then + f_seek = -1 -- end of file + break + end + f_seek = f_seek + nbr_car -- seek to next line + nbr_try = nbr_try + 1 + end + until nbr_try > 20 or f_seek == -1 + io.close(f) + end + + if f_seek ~= -1 then + return -- continue searching... + end + + --Protocol & Sub_protocol + if protocol_name == "" or sub_protocol_name == "" then + lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt) + return + elseif LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + else + lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt) + line = line + 1 + lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt) + line = line + 1 + end + + text1="" + text2="" + for i,v in ipairs(channel_names) do + if i<=8 then + if i==1 then + text1 = v + else + text1=text1 .. "," .. v + end + else + if i==9 then + text2 = v + else + text2=text2 .. "," .. v + end + end + end + if LCD_W > 128 then + lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt) + line = line + 1 + if text2 ~= "" then + lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt) + line = line + 1 + end + end + + if event ~= EVT_VIRTUAL_ENTER and done == 0 then + lcd.drawText(x_pos, y_pos+y_inc*line," Save", lcd_opt + INVERS + BLINK) + return + end + + lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt) + line = line + 1 + local output, nbr + if done == 0 then + for i,v in ipairs(channel_names) do + output = model.getOutput(i-1) + output["name"] = v + model.setOutput(i-1,output) + nbr = i + end + for i = nbr, 15 do + output = model.getOutput(i) + output["name"] = "n-a" + model.setOutput(i,output) + end + if bind_ch == 1 then + output = model.getOutput(15) + output["name"] = "BindCH" + model.setOutput(15,output) + end + done = 1 + end + lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt) + line = line + 1 +end + +-- Init +local function Multi_Init() + module_conf = model.getModule(0) + if module_conf["Type"] ~= 6 then + module_pos = "External" + module_conf = model.getModule(1) + if module_conf["Type"] ~= 6 then + return + end + end + + protocol = module_conf["protocol"] + sub_protocol = module_conf["subProtocol"] + + --Exceptions on first 4 channels... + local stick_names = { "Rud", "Ele", "Thr", "Ail" } + if ( protocol == 4 and sub_protocol == 1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX + stick_names[2] = "n-a" + stick_names[4] = "n-a" + elseif protocol == 43 then -- Traxxas + stick_names[2] = "Aux4" + stick_names[4] = "Aux3" + elseif ( protocol == 48 and sub_protocol == 0 ) then -- V761 3CH + stick_names[4] = "n-a" + elseif protocol == 47 or protocol == 49 or ( protocol == 58 and sub_protocol < 2 ) then -- GD00x, KF606, FX816 + stick_names[1] = "n-a" + stick_names[2] = "n-a" + end + + --Determine fist 4 channels order + local ch_order=module_conf["channelsOrder"] + if (ch_order == -1) then + channel_names[1] = stick_names[defaultChannel(0)+1] + channel_names[2] = stick_names[defaultChannel(1)+1] + channel_names[3] = stick_names[defaultChannel(2)+1] + channel_names[4] = stick_names[defaultChannel(3)+1] + else + channel_names[bitand(ch_order,3)+1] = stick_names[4] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[2] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[3] + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = stick_names[1] + end + + --Exceptions on first 4 channels... + if ( protocol == 73 or (protocol == 74 and sub_protocol == 0) or (protocol == 60 and sub_protocol == 2) or protocol == 89) then -- Kyosho or RadioLink Surface or Pelikan/SCX24 or Losi + channel_names[1] = "ST" + channel_names[2] = "THR" + channel_names[3] = "CH3" + if(protocol == 60 and sub_protocol == 2) then + channel_names[4] = "n-a" + else + channel_names[4] = "CH4" + end + end + if ( protocol == 6 and sub_protocol == 5 ) then -- DSMR + channel_names[1] = "ST" + channel_names[2] = "THR" + channel_names[3] = "AUX1" + channel_names[4] = "AUX2" + end + if ( protocol == 90 ) then -- Mould King + channel_names[1] = "A" + channel_names[2] = "B" + channel_names[3] = "C" + channel_names[4] = "D" + end + + --Check MultiChan.txt + local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r") + if f == nil then return end + file_ok = 1 + io.close(f) +end + +-- Main +local function Multi_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + else + Multi_Draw_LCD(event) + if event == EVT_VIRTUAL_EXIT then + return 2 + end + end + return 0 +end + +return { init=Multi_Init, run=Multi_Run } diff --git a/SCRIPTS/TOOLS/MultiConfig.lua b/SCRIPTS/TOOLS/MultiConfig.lua new file mode 100644 index 0000000..01042fe --- /dev/null +++ b/SCRIPTS/TOOLS/MultiConfig.lua @@ -0,0 +1,533 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### + + +--############################################################################### +-- Multi buffer for Config description +-- To start operation: +-- Write 0xFF at address 4 will request the buffer to be cleared +-- Write "Conf" at address 0..3 +-- Read +-- Read at address 12 gives the current config page +-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters +-- Write +-- Write at address 5..11 the command +-- Write 0x01 at address 4 will send the command to the module +-- !! Before exiting the script must write 0 at address 0 for normal operation !! +--############################################################################### + +local Version = "v0.2" +local Focus = -1 +local Page = 0 +local Edit = -1 +local Edit_pos = 1 +local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""}, + {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} } +local Menu_value = {} +local Blink = 0 +local ModuleNumber = 0 +local ModuleType = "" +local Module = {} +local InitialProtocol = 0 +local InitialSubProtocol = 0 + +function bitand(a, b) + local result = 0 + local bitval = 1 + while a > 0 and b > 0 do + if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits + result = result + bitval -- set the current bit + end + bitval = bitval * 2 -- shift left + a = math.floor(a/2) -- shift right + b = math.floor(b/2) + end + return result +end + +local function Config_Send(page, line, value) + local i + i = (page*16) + line + multiBuffer( 5, i ) + for i = 1 , 6 , 1 do + multiBuffer( 5+i, value[i] ) + end + multiBuffer( 4, 1 ) +end + +local function Config_Release() + --Set the protocol back to what it was + Module.protocol = InitialProtocol + Module.subProtocol = InitialSubProtocol + model.setModule(ModuleNumber, Module) + + --Stop requesting updates + local i + for i = 3 , 0 , -1 do + multiBuffer( i, 0 ) + end +end + +local function Config_Page( ) + Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 }) +end + +local function Config_Draw_Edit( event ) + local i + local text + + if Menu[Focus].field_type == 0xD0 then + -- Editable Hex value + if Edit == -1 then + -- Init + Edit = 0 + Edit_pos = 1 + Blink = 0 + for i = 1, Menu[Focus].field_len, 1 do + Menu_value[i] = Menu[Focus].field_value[i] + end + end + if Edit == 0 then + -- Not editing value + if event == EVT_VIRTUAL_ENTER then + if Edit_pos > Menu[Focus].field_len then + -- Save or Cancel + Edit = -1 + if Edit_pos == Menu[Focus].field_len + 1 then + -- Save + Config_Send(Page, Focus, Menu_value) + end + return + else + -- Switch to edit mode + Edit = 1 + end + elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then + -- Move cursor + Edit_pos = Edit_pos - 1 + elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then + -- Move cursor + Edit_pos = Edit_pos + 1 + end + else + -- Editing value + if event == EVT_VIRTUAL_ENTER then + -- End edit + Edit = 0 + elseif event == EVT_VIRTUAL_PREV then + -- Change value + if Menu_value[Edit_pos] > 0 then + Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1 + end + elseif event == EVT_VIRTUAL_NEXT then + -- Change value + if Menu_value[Edit_pos] < 255 then + Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1 + end + end + --Blink + Blink = Blink + 1 + if Blink > 30 then + Blink = 0 + end + end + --Display + if LCD_W == 480 then + lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR) + lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR) + else + lcd.clear() + end + for i = 1, Menu[Focus].field_len, 1 do + if i==Edit_pos and (Edit ~= 1 or Blink > 15) then + attrib = INVERS + else + attrib = 0 + end + if LCD_W == 480 then + lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib) + else + lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE) + end + end + if Edit_pos == Menu[Focus].field_len + 1 then + attrib = INVERS + else + attrib = 0 + end + if LCD_W == 480 then + lcd.drawText(170, 130, "Save", attrib) + else + lcd.drawText(17, 30, "Save", attrib + SMLSIZE) + end + if Edit_pos == Menu[Focus].field_len + 2 then + attrib = INVERS + else + attrib = 0 + end + if LCD_W == 480 then + lcd.drawText(260, 130, "Cancel", attrib) + else + lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE) + end + + elseif Menu[Focus].field_type == 0x90 then + -- Action text + if Edit == -1 then + -- Init + Edit = 0 + Edit_pos = 2 + end + if event == EVT_VIRTUAL_ENTER then + -- Exit + Edit = -1 + if Edit_pos == 1 then + -- Yes + Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } ) + end + return + elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then + -- Switch to Yes + Edit_pos = Edit_pos - 1 + elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then + -- Switch to No + Edit_pos = Edit_pos + 1 + end + -- Display + if LCD_W == 480 then + lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR) + lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR) + else + lcd.clear() + end + if LCD_W == 480 then + lcd.drawText(170, 110, Menu[Focus].field_text .. "?") + else + lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE) + end + if Edit_pos == 1 then + attrib = INVERS + else + attrib = 0 + end + if LCD_W == 480 then + lcd.drawText(170, 130, "Yes", attrib) + else + lcd.drawText(17, 30, "Yes", attrib + SMLSIZE) + end + if Edit_pos == 2 then + attrib = INVERS + else + attrib = 0 + end + if LCD_W == 480 then + lcd.drawText(260, 130, "No", attrib) + else + lcd.drawText(77, 30, "No", attrib) + end + end +end + +local function Config_Next_Prev( event ) +-- Next Prev on main menu + local line + if event == EVT_VIRTUAL_PREV then + for line = Focus - 1, 1, -1 do + if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then + Focus = line + break + end + end + elseif event == EVT_VIRTUAL_NEXT then + for line = Focus + 1, 7, 1 do + if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then + Focus = line + break + end + end + end +end + +local function Config_Draw_Menu() +-- Main menu + local i + local value + local line + local length + local text + + lcd.clear() + + if LCD_W == 480 then + --Draw title + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR) + if multiBuffer(13) == 0x00 then + lcd.drawText(10,50,"No Config telemetry...", BLINK) + end + else + --Draw on LCD_W=128 + lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE) + if multiBuffer(13) == 0x00 then + lcd.drawText(2,17,"No Config telemetry...",SMLSIZE) + end + end + + if multiBuffer(13) ~= 0x00 then + if LCD_W == 480 then + --Draw firmware version and channels order + local ch_order = multiBuffer(17) + local channel_names = {} + channel_names[bitand(ch_order,3)+1] = "A" + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = "E" + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = "T" + ch_order = math.floor(ch_order/4) + channel_names[bitand(ch_order,3)+1] = "R" + lcd.drawText(150, 5, ModuleType.." v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR) + else + lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4]) + end + + --Draw Menu + for line = 1, 7, 1 do + --Clear line info + Menu[line].text = "" + Menu[line].field_type = 0 + Menu[line].field_len = 0 + for i = 1, 7, 1 do + Menu[line].field_value[i] = 0 + end + Menu[line].field_text = "" + length = 0 + --Read line from buffer + for i = 0, 20-1, 1 do + value=multiBuffer( line*20+13+i ) + if value > 0x80 and Menu[line].field_type == 0 then + -- Read field type + Menu[line].field_type = bitand(value, 0xF0) + Menu[line].field_len = bitand(value, 0x0F) + length = Menu[line].field_len + if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then + -- First actionnable field if nothing was selected + Focus = line; + end + else + if Menu[line].field_type == 0 then + -- Text + if value == 0 then + break -- end of line + end + Menu[line].text = Menu[line].text .. string.char(value) + else + -- Menu specific fields + length = length - 1 + if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then + Menu[line].field_text = Menu[line].field_text .. string.char(value) + else + Menu[line].field_value[Menu[line].field_len-length] = value + end + if length == 0 then + -- End of fields + break + end + end + end + end + -- Display menu text + if Menu[line].text ~= "" then + if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then + Menu[line].text = Menu[line].text .. ":" + end + if LCD_W == 480 then + lcd.drawText(10,32+20*line,Menu[line].text ) + else + lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE) + end + end + -- Display specific fields + if line == Focus then + attrib = INVERS + else + attrib = 0 + end + if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then + -- Text + if LCD_W == 480 then + lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib) + else + lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib) + end + elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then + -- Decimal value + value = 0 + for i = 1, Menu[line].field_len, 1 do + value = value*256 + value + end + if LCD_W == 480 then + lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib) + else + lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib) + end + elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then + -- Hex value + text="" + for i = 1, Menu[line].field_len, 1 do + text = text .. string.format('%02X ', Menu[line].field_value[i]) + end + if LCD_W == 480 then + lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib) + else + lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib) + end + end + end + end +end + +-- Init +local function Config_Init() + --Find Multi module + Module_int = model.getModule(0) + Module_ext = model.getModule(1) + if Module_int["Type"] ~= 6 and Module_ext["Type"] ~= 6 then + error("No Multi module detected...") + return 2 + end + if Module_int["Type"] == 6 and Module_ext["Type"] == 6 then + error("Two Multi modules detected, turn on only the one to be configured.") + return 2 + end + if Module_int["Type"] == 6 then + ModuleNumber = 0 + ModuleType = "Internal" + else + ModuleNumber = 1 + ModuleType = "External" + end + --Get Module settings and set it to config protocol + Module = model.getModule(ModuleNumber) + InitialProtocol = Module.protocol + InitialSubProtocol = Module.subProtocol + Module.protocol = 86 + Module.subProtocol = 0 + model.setModule(ModuleNumber, Module) + --pause while waiting for the module to switch to config + for i = 0, 10, 1 do end + + --Set protocol to talk to + multiBuffer( 0, string.byte('C') ) + --test if value has been written + if multiBuffer( 0 ) ~= string.byte('C') then + error("Not enough memory!") + return 2 + end + + --Request init of the buffer + multiBuffer( 4, 0xFF ) + multiBuffer(13, 0x00 ) + + --Continue buffer init + multiBuffer( 1, string.byte('o') ) + multiBuffer( 2, string.byte('n') ) + multiBuffer( 3, string.byte('f') ) + + -- Test set + -- multiBuffer( 12, 0 ) + -- multiBuffer( 13, 1 ) + -- multiBuffer( 14, 3 ) + -- multiBuffer( 15, 2 ) + -- multiBuffer( 16, 62 ) + -- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64) + + -- multiBuffer( 33, string.byte('G') ) + -- multiBuffer( 34, string.byte('l') ) + -- multiBuffer( 35, string.byte('o') ) + -- multiBuffer( 36, string.byte('b') ) + -- multiBuffer( 37, string.byte('a') ) + -- multiBuffer( 38, string.byte('l') ) + -- multiBuffer( 39, string.byte(' ') ) + -- multiBuffer( 40, string.byte('I') ) + -- multiBuffer( 41, string.byte('D') ) + -- multiBuffer( 42, 0xD0 + 4 ) + -- multiBuffer( 43, 0x12 ) + -- multiBuffer( 44, 0x34 ) + -- multiBuffer( 45, 0x56 ) + -- multiBuffer( 46, 0x78 ) + -- multiBuffer( 47, 0x9A ) + -- multiBuffer( 48, 0xBC ) + + -- multiBuffer( 53, 0x90 + 9 ) + -- multiBuffer( 54, string.byte('R') ) + -- multiBuffer( 55, string.byte('e') ) + -- multiBuffer( 56, string.byte('s') ) + -- multiBuffer( 57, string.byte('e') ) + -- multiBuffer( 58, string.byte('t') ) + -- multiBuffer( 59, string.byte(' ') ) + -- multiBuffer( 60, string.byte('G') ) + -- multiBuffer( 61, string.byte('I') ) + -- multiBuffer( 62, string.byte('D') ) + -- multiBuffer( 63, 0x00 ) +end + +-- Main +local function Config_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + Config_Release() + return 2 + else + Config_Draw_Menu() + if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then + -- Not editing, ok to change page + if event == EVT_VIRTUAL_PREV_PAGE then + killEvents(event) + if Page > 0 then + --Page = Page - 1 + --Config_Page() + end + else + --Page = Page + 1 + --Config_Page() + end + end + if Focus > 0 then + -- At least one line has an action + if Edit >= 0 then + -- Currently editing + Config_Draw_Edit( event ) + elseif event == EVT_VIRTUAL_ENTER then + -- Switch to edit + Config_Draw_Edit( 0 ) + elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then + -- Main menu selection + Config_Next_Prev( event ) + end + end + return 0 + end +end + +return { init=Config_Init, run=Config_Run } diff --git a/SCRIPTS/TOOLS/MultiLOLI.lua b/SCRIPTS/TOOLS/MultiLOLI.lua new file mode 100644 index 0000000..4d309e3 --- /dev/null +++ b/SCRIPTS/TOOLS/MultiLOLI.lua @@ -0,0 +1,221 @@ + +local toolName = "TNS|Multi LOLI RX config|TNE" + +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 loli_nok = false +local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1 + { 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2 + { -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3 + { -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4 + { 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5 + { -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6 + { 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7 + { -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8 + +local sel = 1 +local edit = false + +local blink = 0 +local BLINK_SPEED = 15 + +local function drawScreenTitle(title) + if LCD_W == 480 then + lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) + lcd.drawText(1, 5, title, MENU_TITLE_COLOR) + else + lcd.drawScreenTitle(title, 0, 0) + end +end + +local function LOLI_Draw_LCD(event) + local line = 0 + + lcd.clear() + + --Display settings + local lcd_opt = 0 + if LCD_W == 480 then + drawScreenTitle("Multi - LOLI RX configuration tool") + x_pos = 152 + x_inc = 90 + y_pos = 40 + y_inc = 20 + else + x_pos = 5 + x_inc = 30 + y_pos = 1 + y_inc = 8 + lcd_opt = SMLSIZE + end + + --Multi Module detection + if loli_nok then + if LCD_W == 480 then + lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt) + else + --Draw on LCD_W=128 + lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE) + end + return + end + + --Display current config + if LCD_W == 480 then + line = line + 1 + lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt) + lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt) + lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188) + lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0) + lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0) + line = line + 1 + end + + local out + for i = 1, 8 do + out = getValue("ch"..(i+8)) + lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt) + for j = 1, #channels[i], 3 do + if out > channels[i][j] then + if sel == i then + invert = INVERS + if edit == true then + blink = blink + 1 + if blink > BLINK_SPEED then + invert = 0 + if blink > BLINK_SPEED * 2 then + blink = 0 + end + end + end + else + invert = 0 + end + lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert) + break + end + end + line = line + 1 + end +end + +local function LOLI_Change_Value(dir) + local pos = 0 + local out + --look for the current position + out = getValue("ch"..(sel+8)) + for j = 1, #channels[sel], 3 do + if out > channels[sel][j] then + pos = j + break + end + end + + --decrement or increment + if dir < 0 and pos > 1 then + pos = pos - 3 + elseif dir > 0 and pos + 3 < #channels[sel] then + pos = pos + 3 + else + return + end + + --delete all mixers for the selected channel + local num_mix = model.getMixesCount(sel-1 +8) + for i = 1, num_mix do + model.deleteMix(sel-1 +8, 0); + end + + --create new mixer + local source_max = getFieldInfo("cyc1") + + local val = { name = channels[sel][pos+1], + source = source_max.id - 1, -- MAX=100 on TX16S + weight = channels[sel][pos+2], + offset = 0, + switch = 0, + multiplex = 0, + curveType = 0, + curveValue = 0, + flightModes = 0, + carryTrim = false, + mixWarn = 0, + delayUp = 0, + delayDown = 0, + speedUp = 0, + speedDown = 0 } + model.insertMix(sel-1 +8, 0, val) +end + +local function LOLI_Menu(event) + if event == EVT_VIRTUAL_NEXT then + if edit == false then + -- not changing a value + if sel < 8 then + sel = sel + 1 + end + else + -- need to inc the value + LOLI_Change_Value(1) + end + elseif event == EVT_VIRTUAL_PREV then + if edit == false then + -- not changing a value + if sel > 1 then + sel = sel - 1 + end + else + -- need to dec the value + LOLI_Change_Value(-1) + end + elseif event == EVT_VIRTUAL_ENTER then + if edit == false then + edit = true + blink = BLINK_SPEED + else + edit = false + end + end +end + +-- Init +local function LOLI_Init() + local module_conf = model.getModule(0) + if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then + module_conf = model.getModule(1) + if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then + loli_nok = true + end + end +end + +-- Main +local function LOLI_Run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_EXIT then + return 2 + else + LOLI_Menu(event) + LOLI_Draw_LCD(event) + return 0 + end +end + +return { init=LOLI_Init, run=LOLI_Run } diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/error.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/error.luac new file mode 100755 index 0000000..0ab504e Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/error.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/file.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/file.luac new file mode 100755 index 0000000..c9a1cb7 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/file.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/gui.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/gui.luac new file mode 100755 index 0000000..67d1752 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/gui.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/radio.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/radio.luac new file mode 100755 index 0000000..51c9bf9 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/radio.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winBW.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winBW.luac new file mode 100755 index 0000000..2d2fc33 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winBW.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winC.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winC.luac new file mode 100755 index 0000000..63a66af Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/LIB/winC.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/Fusion.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/Fusion.png new file mode 100755 index 0000000..79ac095 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/Fusion.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSAgentLite.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSAgentLite.png new file mode 100755 index 0000000..b50d087 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSAgentLite.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSwifi.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSwifi.png new file mode 100755 index 0000000..ab6c235 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TBSwifi.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRrxm.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRrxm.png new file mode 100755 index 0000000..c99bf50 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRrxm.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRtxm.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRtxm.png new file mode 100755 index 0000000..0f4ed33 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/TRtxm.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFTango2.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFTango2.png new file mode 100755 index 0000000..2d16772 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFTango2.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFardu.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFardu.png new file mode 100755 index 0000000..daa84ee Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFardu.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFkiss.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFkiss.png new file mode 100755 index 0000000..b8c0807 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFkiss.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxm.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxm.png new file mode 100755 index 0000000..8d3f325 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxm.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxmd.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxmd.png new file mode 100755 index 0000000..0854e48 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFrxmd.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxf.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxf.png new file mode 100755 index 0000000..7e5b989 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxf.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxm.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxm.png new file mode 100755 index 0000000..9a320f0 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFtxm.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32hv.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32hv.png new file mode 100755 index 0000000..dc371a5 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32hv.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32n.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32n.png new file mode 100755 index 0000000..457e21c Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFu32n.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFuevo.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFuevo.png new file mode 100755 index 0000000..6353d0e Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/XFuevo.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/cloud.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/cloud.png new file mode 100755 index 0000000..f43f82e Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/cloud.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/frame.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/frame.png new file mode 100755 index 0000000..872e5a8 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/frame.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/txmod.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/txmod.png new file mode 100755 index 0000000..6abf55e Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/txmod.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogo.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogo.png new file mode 100755 index 0000000..b049044 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogo.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoOFF.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoOFF.png new file mode 100755 index 0000000..0ef5198 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoOFF.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoON.png b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoON.png new file mode 100755 index 0000000..8a3a91c Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/C/wgtlogoON.png differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/cloud.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/cloud.bmp new file mode 100755 index 0000000..088623d Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/cloud.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS1.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS1.bmp new file mode 100755 index 0000000..1cd2a3b Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS1.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS2.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS2.bmp new file mode 100755 index 0000000..300d424 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tbs_splashGS2.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tr.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tr.bmp new file mode 100755 index 0000000..700d52e Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/tr.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/wifi.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/wifi.bmp new file mode 100755 index 0000000..cb4be50 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/wifi.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/xf.bmp b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/xf.bmp new file mode 100755 index 0000000..66591f8 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/GFX/GS/xf.bmp differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/0.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/0.luac new file mode 100755 index 0000000..552ceac Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/0.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/10.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/10.luac new file mode 100755 index 0000000..f942278 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/10.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/11.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/11.luac new file mode 100755 index 0000000..1552c74 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/11.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/13.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/13.luac new file mode 100755 index 0000000..07ccffa Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/13.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/9.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/9.luac new file mode 100755 index 0000000..5886be6 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/9.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/dev.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/dev.luac new file mode 100755 index 0000000..2831dc2 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/dev.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/fld.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/fld.luac new file mode 100755 index 0000000..90aae4c Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/fld.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/main.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/main.luac new file mode 100755 index 0000000..91079fe Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/P/main.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiBW.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiBW.luac new file mode 100755 index 0000000..2b4d98c Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiBW.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiC.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiC.luac new file mode 100755 index 0000000..be2c6a7 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiC.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiGS.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiGS.luac new file mode 100755 index 0000000..aa9cec8 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/cuiGS.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/main.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/main.luac new file mode 100755 index 0000000..90f068b Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/main.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW10.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW10.luac new file mode 100755 index 0000000..7c09a99 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW10.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW13.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW13.luac new file mode 100755 index 0000000..be9dc3c Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW13.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW8.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW8.luac new file mode 100755 index 0000000..9a6e8f3 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popBW8.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC10.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC10.luac new file mode 100755 index 0000000..8dca5bc Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC10.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC13.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC13.luac new file mode 100755 index 0000000..6ad8639 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC13.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC8.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC8.luac new file mode 100755 index 0000000..c4d48e3 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popC8.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS10.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS10.luac new file mode 100755 index 0000000..15a9a53 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS10.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS13.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS13.luac new file mode 100755 index 0000000..3588991 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS13.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS8.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS8.luac new file mode 100755 index 0000000..9128188 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/UI/popGS8.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/setup.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/setup.luac new file mode 100755 index 0000000..d87b832 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/SETUP/setup.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/loader.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/loader.luac new file mode 100755 index 0000000..64651f5 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/loader.luac differ diff --git a/SCRIPTS/TOOLS/TBSAGENTLITE/splash.luac b/SCRIPTS/TOOLS/TBSAGENTLITE/splash.luac new file mode 100755 index 0000000..629e470 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAGENTLITE/splash.luac differ diff --git a/SCRIPTS/TOOLS/TBSAgentLite.lua b/SCRIPTS/TOOLS/TBSAgentLite.lua new file mode 100755 index 0000000..55b5689 --- /dev/null +++ b/SCRIPTS/TOOLS/TBSAgentLite.lua @@ -0,0 +1,8 @@ +-------------------------------------------------------------------------------- +-- TBS Agent Lite 0.95 +-- release date: 2021-11 +-- author: JimB40 +-------------------------------------------------------------------------------- +local toolName = "TNS|TBS Agent Lite|TNE" +local SP = '/SCRIPTS/TOOLS/TBSAGENTLITE/' +return {run=(loadScript(SP..'loader','Tx')(SP)).run} diff --git a/SCRIPTS/TOOLS/TBSAgentLite.luac b/SCRIPTS/TOOLS/TBSAgentLite.luac new file mode 100755 index 0000000..237cae4 Binary files /dev/null and b/SCRIPTS/TOOLS/TBSAgentLite.luac differ diff --git a/SCRIPTS/TOOLS/WizardLoader.lua b/SCRIPTS/TOOLS/WizardLoader.lua new file mode 100755 index 0000000..686b1b2 --- /dev/null +++ b/SCRIPTS/TOOLS/WizardLoader.lua @@ -0,0 +1,11 @@ +local toolName = "TNS|Wizard Loader|TNE" + +local function init() +end + +local function run(event) + chdir("/SCRIPTS/WIZARD") + return "/SCRIPTS/WIZARD/wizard.lua" +end + +return {init = init, run = run} diff --git a/SCRIPTS/TOOLS/WizardLoader.luac b/SCRIPTS/TOOLS/WizardLoader.luac new file mode 100755 index 0000000..7b4780a Binary files /dev/null and b/SCRIPTS/TOOLS/WizardLoader.luac differ diff --git a/SCRIPTS/TOOLS/elrsV3.lua b/SCRIPTS/TOOLS/elrsV3.lua new file mode 100755 index 0000000..649a3e0 --- /dev/null +++ b/SCRIPTS/TOOLS/elrsV3.lua @@ -0,0 +1,945 @@ +-- TNS|ExpressLRS|TNE +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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 deviceId = 0xEE +local handsetId = 0xEF +local deviceName = "" +local lineIndex = 1 +local pageOffset = 0 +local edit = nil +local charIndex = 1 +local fieldPopup +local fieldTimeout = 0 +local loadQ = {} +local fieldChunk = 0 +local fieldData = {} +local fields = {} +local devices = {} +local goodBadPkt = "?/??? ?" +local elrsFlags = 0 +local elrsFlagsInfo = "" +local fields_count = 0 +local backButtonId = 2 +local exitButtonId = 3 +local devicesRefreshTimeout = 50 +local folderAccess = nil +local commandRunningIndicator = 1 +local expectChunksRemain = -1 +local deviceIsELRS_TX = nil +local linkstatTimeout = 100 +local titleShowWarn = nil +local titleShowWarnTimeout = 100 +local exitscript = 0 + +local COL2 +local maxLineIndex +local textXoffset +local textYoffset +local textSize +local byteToStr + +local function allocateFields() + fields = {} + for i=1, fields_count + 2 + #devices do + fields[i] = { } + end + backButtonId = fields_count + 2 + #devices + fields[backButtonId] = {name="----BACK----", parent = 255, type=14} + if folderAccess ~= nil then + fields[backButtonId].parent = folderAccess + end + exitButtonId = backButtonId + 1 + fields[exitButtonId] = {id = exitButtonId, name="----EXIT----", type=17} +end + +local function reloadAllField() + fieldChunk = 0 + fieldData = {} + -- loadQ is actually a stack + loadQ = {} + for fieldId = fields_count, 1, -1 do + loadQ[#loadQ+1] = fieldId + end +end + +local function getField(line) + local counter = 1 + for i = 1, #fields do + local field = fields[i] + if folderAccess == field.parent and not field.hidden then + if counter < line then + counter = counter + 1 + else + return field + end + end + end +end + +local function constrain(x, low, high) + if x < low then + return low + elseif x > high then + return high + end + return x +end + +-- Change display attribute to current field +local function incrField(step) + local field = getField(lineIndex) + local min, max = 0, 0 + if ((field.type <= 5) or (field.type == 8)) then + min = field.min or 0 + max = field.max or 0 + step = field.step * step + elseif field.type == 9 then + min = 0 + max = #field.values - 1 + end + field.value = constrain(field.value + step, min, max) +end + +-- Select the next or previous editable field +local function selectField(step) + local newLineIndex = lineIndex + local field + repeat + newLineIndex = newLineIndex + step + if newLineIndex <= 0 then + newLineIndex = #fields + elseif newLineIndex == 1 + #fields then + newLineIndex = 1 + pageOffset = 0 + end + field = getField(newLineIndex) + until newLineIndex == lineIndex or (field and field.name) + lineIndex = newLineIndex + if lineIndex > maxLineIndex + pageOffset then + pageOffset = lineIndex - maxLineIndex + elseif lineIndex <= pageOffset then + pageOffset = lineIndex - 1 + end +end + +local function fieldGetSelectOpts(data, offset, last) + if last then + while data[offset] ~= 0 do + offset = offset + 1 + end + return last, offset + 1 + end + + -- Split a table of byte values (string) with ; separator into a table + local r = {} + local opt = '' + local b = data[offset] + while b ~= 0 do + if b == 59 then -- ';' + r[#r+1] = opt + opt = '' + else + opt = opt .. byteToStr(b) + end + offset = offset + 1 + b = data[offset] + end + + r[#r+1] = opt + opt = nil + return r, offset + 1, collectgarbage("collect") +end + +local function fieldGetString(data, offset, last) + if last then + return last, offset + #last + 1 + end + + local result = "" + while data[offset] ~= 0 do + result = result .. byteToStr(data[offset]) + offset = offset + 1 + end + + return result, offset + 1, collectgarbage("collect") +end + +local function getDevice(name) + for i=1, #devices do + if devices[i].name == name then + return devices[i] + end + end +end + +local function fieldGetValue(data, offset, size) + local result = 0 + for i=0, size-1 do + result = bit32.lshift(result, 8) + data[offset + i] + end + return result +end + +local function fieldUnsignedLoad(field, data, offset, size) + field.value = fieldGetValue(data, offset, size) + field.min = fieldGetValue(data, offset+size, size) + field.max = fieldGetValue(data, offset+2*size, size) + --field.default = fieldGetValue(data, offset+3*size, size) + field.unit = fieldGetString(data, offset+4*size, field.unit) + field.step = 1 +end + +local function fieldUnsignedToSigned(field, size) + local bandval = bit32.lshift(0x80, (size-1)*8) + field.value = field.value - bit32.band(field.value, bandval) * 2 + field.min = field.min - bit32.band(field.min, bandval) * 2 + field.max = field.max - bit32.band(field.max, bandval) * 2 + --field.default = field.default - bit32.band(field.default, bandval) * 2 +end + +local function fieldSignedLoad(field, data, offset, size) + fieldUnsignedLoad(field, data, offset, size) + fieldUnsignedToSigned(field, size) +end + +local function fieldIntSave(index, value, size) + local frame = { deviceId, handsetId, index } + for i=size-1, 0, -1 do + frame[#frame + 1] = (bit32.rshift(value, 8*i) % 256) + end + crossfireTelemetryPush(0x2D, frame) +end + +local function fieldUnsignedSave(field, size) + local value = field.value + fieldIntSave(field.id, value, size) +end + +local function fieldSignedSave(field, size) + local value = field.value + if value < 0 then + value = bit32.lshift(0x100, (size-1)*8) + value + end + fieldIntSave(field.id, value, size) +end + +local function fieldIntDisplay(field, y, attr) + lcd.drawText(COL2, y, field.value .. field.unit, attr) +end + +-- UINT8 +local function fieldUint8Load(field, data, offset) + fieldUnsignedLoad(field, data, offset, 1) +end + +local function fieldUint8Save(field) + fieldUnsignedSave(field, 1) +end + +-- INT8 +local function fieldInt8Load(field, data, offset) + fieldSignedLoad(field, data, offset, 1) +end + +local function fieldInt8Save(field) + fieldSignedSave(field, 1) +end + +-- UINT16 +local function fieldUint16Load(field, data, offset) + fieldUnsignedLoad(field, data, offset, 2) +end + +local function fieldUint16Save(field) + fieldUnsignedSave(field, 2) +end + +-- INT16 +local function fieldInt16Load(field, data, offset) + fieldSignedLoad(field, data, offset, 2) +end + +local function fieldInt16Save(field) + fieldSignedSave(field, 2) +end + +-- TEXT SELECTION +local function fieldTextSelectionLoad(field, data, offset) + field.values, offset = fieldGetSelectOpts(data, offset, field.nc == nil and field.values) + field.value = data[offset] + -- min max and default (offset+1 to 3) are not used on selections + -- units never uses cache + field.unit = fieldGetString(data, offset+4) + field.nc = nil -- use cache next time +end + +local function fieldTextSelectionSave(field) + crossfireTelemetryPush(0x2D, { deviceId, handsetId, field.id, field.value }) +end + +local function fieldTextSelectionDisplay_color(field, y, attr) + local val = field.values[field.value+1] or "ERR" + lcd.drawText(COL2, y, val, attr) + local strPix = lcd.sizeText and lcd.sizeText(val) or (10 * #val) + lcd.drawText(COL2 + strPix, y, field.unit, 0) +end + +local function fieldTextSelectionDisplay_bw(field, y, attr) + lcd.drawText(COL2, y, field.values[field.value+1] or "ERR", attr) + lcd.drawText(lcd.getLastPos(), y, field.unit, 0) +end + +-- STRING +local function fieldStringLoad(field, data, offset) + field.value, offset = fieldGetString(data, offset) + if #data >= offset then + field.maxlen = data[offset] + end +end + +local function fieldStringDisplay(field, y, attr) + lcd.drawText(COL2, y, field.value, attr) +end + +local function fieldFolderOpen(field) + folderAccess = field.id + local backFld = fields[backButtonId] + -- Store the lineIndex and pageOffset to return to in the backFld + backFld.li = lineIndex + backFld.po = pageOffset + backFld.parent = folderAccess + + lineIndex = 1 + pageOffset = 0 +end + +local function fieldFolderDeviceOpen(field) + crossfireTelemetryPush(0x28, { 0x00, 0xEA }) --broadcast with standard handset ID to get all node respond correctly + return fieldFolderOpen(field) +end + +local function fieldFolderDisplay(field,y ,attr) + lcd.drawText(textXoffset, y, "> " .. field.name, bit32.bor(attr, BOLD)) +end + +local function fieldCommandLoad(field, data, offset) + field.status = data[offset] + field.timeout = data[offset+1] + field.info = fieldGetString(data, offset+2) + if field.status == 0 then + fieldPopup = nil + end +end + +local function fieldCommandSave(field) + if field.status ~= nil then + if field.status < 4 then + field.status = 1 + crossfireTelemetryPush(0x2D, { deviceId, handsetId, field.id, field.status }) + fieldPopup = field + fieldPopup.lastStatus = 0 + commandRunningIndicator = 1 + fieldTimeout = getTime() + field.timeout + end + end +end + +local function fieldCommandDisplay(field, y, attr) + lcd.drawText(10, y, "[" .. field.name .. "]", bit32.bor(attr, BOLD)) +end + +local function UIbackExec() + local backFld = fields[backButtonId] + lineIndex = backFld.li or 1 + pageOffset = backFld.po or 0 + + backFld.parent = 255 + backFld.li = nil + backFld.po = nil + folderAccess = nil +end + +local function UIexitExec() + exitscript = 1 +end + +local function changeDeviceId(devId) --change to selected device ID + folderAccess = nil + deviceIsELRS_TX = nil + elrsFlags = 0 + --if the selected device ID (target) is a TX Module, we use our Lua ID, so TX Flag that user is using our LUA + if devId == 0xEE then + handsetId = 0xEF + else --else we would act like the legacy lua + handsetId = 0xEA + end + deviceId = devId + fields_count = 0 --set this because next target wouldn't have the same count, and this trigger to request the new count +end + +local function fieldDeviceIdSelect(field) + local device = getDevice(field.name) + changeDeviceId(device.id) + crossfireTelemetryPush(0x28, { 0x00, 0xEA }) +end + +local function createDeviceFields() -- put other devices in the field list + fields[fields_count + 2 + #devices] = fields[backButtonId] + backButtonId = fields_count + 2 + #devices -- move back button to the end of the list, so it will always show up at the bottom. + for i=1, #devices do + if devices[i].id == deviceId then + fields[fields_count+1+i] = {name=devices[i].name, parent = 255, type=15} + else + fields[fields_count+1+i] = {name=devices[i].name, parent = fields_count+1, type=15} + end + end +end + +local function parseDeviceInfoMessage(data) + local offset + local id = data[2] + local newName + newName, offset = fieldGetString(data, 3) + local device = getDevice(newName) + if device == nil then + device = { id = id, name = newName } + devices[#devices + 1] = device + end + if deviceId == id then + deviceName = newName + deviceIsELRS_TX = ((fieldGetValue(data,offset,4) == 0x454C5253) and (deviceId == 0xEE)) or nil -- SerialNumber = 'E L R S' and ID is TX module + local newFieldCount = data[offset+12] + if newFieldCount ~= fields_count or newFieldCount == 0 then + fields_count = newFieldCount + allocateFields() + reloadAllField() + fields[fields_count+1] = {id = fields_count+1, name="Other Devices", parent = 255, type=16} -- add other devices folders + if newFieldCount == 0 then + -- This device has no fields so the Loading code never starts + createDeviceFields() + end + end + end +end + +local functions = { + { load=fieldUint8Load, save=fieldUint8Save, display=fieldIntDisplay }, --1 UINT8(0) + { load=fieldInt8Load, save=fieldInt8Save, display=fieldIntDisplay }, --2 INT8(1) + { load=fieldUint16Load, save=fieldUint16Save, display=fieldIntDisplay }, --3 UINT16(2) + { load=fieldInt16Load, save=fieldInt16Save, display=fieldIntDisplay }, --4 INT16(3) + nil, + nil, + nil, + nil, + nil, --9 FLOAT(8) + { load=fieldTextSelectionLoad, save=fieldTextSelectionSave, display = nil }, --10 SELECT(9) + { load=fieldStringLoad, save=nil, display=fieldStringDisplay }, --11 STRING(10) editing NOTIMPL + { load=nil, save=fieldFolderOpen, display=fieldFolderDisplay }, --12 FOLDER(11) + { load=fieldStringLoad, save=nil, display=fieldStringDisplay }, --13 INFO(12) + { load=fieldCommandLoad, save=fieldCommandSave, display=fieldCommandDisplay }, --14 COMMAND(13) + { load=nil, save=UIbackExec, display=fieldCommandDisplay }, --15 back(14) + { load=nil, save=fieldDeviceIdSelect, display=fieldCommandDisplay }, --16 device(15) + { load=nil, save=fieldFolderDeviceOpen, display=fieldFolderDisplay }, --17 deviceFOLDER(16) + { load=nil, save=UIexitExec, display=fieldCommandDisplay }, --18 exit(17) +} + +local function parseParameterInfoMessage(data) + local fieldId = (fieldPopup and fieldPopup.id) or loadQ[#loadQ] + if data[2] ~= deviceId or data[3] ~= fieldId then + fieldData = {} + fieldChunk = 0 + return + end + local field = fields[fieldId] + local chunksRemain = data[4] + -- If no field or the chunksremain changed when we have data, don't continue + if not field or (chunksRemain ~= expectChunksRemain and #fieldData ~= 0) then + return + end + expectChunksRemain = chunksRemain - 1 + for i=5, #data do + fieldData[#fieldData + 1] = data[i] + end + if chunksRemain > 0 then + fieldChunk = fieldChunk + 1 + else + loadQ[#loadQ] = nil + -- Populate field from fieldData + if #fieldData > 3 then + local offset + field.id = fieldId + field.parent = (fieldData[1] ~= 0) and fieldData[1] or nil + field.type = bit32.band(fieldData[2], 0x7f) + field.hidden = bit32.btest(fieldData[2], 0x80) or nil + field.name, offset = fieldGetString(fieldData, 3, field.name) + if functions[field.type+1].load then + functions[field.type+1].load(field, fieldData, offset) + end + if field.min == 0 then field.min = nil end + if field.max == 0 then field.max = nil end + end + + fieldChunk = 0 + fieldData = {} + + -- Last field loaded, add the list of devices to the end + if #loadQ == 0 then + createDeviceFields() + end + end +end + +local function parseElrsInfoMessage(data) + if data[2] ~= deviceId then + fieldData = {} + fieldChunk = 0 + return + end + + local badPkt = data[3] + local goodPkt = (data[4]*256) + data[5] + local newFlags = data[6] + -- If flags are changing, reset the warning timeout to display/hide message immediately + if newFlags ~= elrsFlags then + elrsFlags = newFlags + titleShowWarnTimeout = 0 + end + elrsFlagsInfo = fieldGetString(data, 7) + + local state = (bit32.btest(elrsFlags, 1) and "C") or "-" + goodBadPkt = string.format("%u/%u %s", badPkt, goodPkt, state) +end + +local function parseElrsV1Message(data) + if (data[1] ~= 0xEA) or (data[2] ~= 0xEE) then + return + end + + -- local badPkt = data[9] + -- local goodPkt = (data[10]*256) + data[11] + -- goodBadPkt = string.format("%u/%u X", badPkt, goodPkt) + fieldPopup = {id = 0, status = 2, timeout = 0xFF, info = "ERROR: 1.x firmware"} + fieldTimeout = getTime() + 0xFFFF +end + +local function refreshNext() + local command, data = crossfireTelemetryPop() + if command == 0x29 then + parseDeviceInfoMessage(data) + elseif command == 0x2B then + parseParameterInfoMessage(data) + if #loadQ > 0 then + fieldTimeout = 0 -- request next chunk immediately + elseif fieldPopup then + fieldTimeout = getTime() + fieldPopup.timeout + end + elseif command == 0x2D then + parseElrsV1Message(data) + elseif command == 0x2E then + parseElrsInfoMessage(data) + end + + local time = getTime() + if fieldPopup then + if time > fieldTimeout and fieldPopup.status ~= 3 then + crossfireTelemetryPush(0x2D, { deviceId, handsetId, fieldPopup.id, 6 }) -- lcsQuery + fieldTimeout = time + fieldPopup.timeout + end + elseif time > devicesRefreshTimeout and fields_count < 1 then + devicesRefreshTimeout = time + 100 -- 1s + crossfireTelemetryPush(0x28, { 0x00, 0xEA }) + elseif time > linkstatTimeout then + if not deviceIsELRS_TX and #loadQ == 0 then + goodBadPkt = "" + else + crossfireTelemetryPush(0x2D, { deviceId, handsetId, 0x0, 0x0 }) --request linkstat + end + linkstatTimeout = time + 100 + elseif time > fieldTimeout and fields_count ~= 0 then + if #loadQ > 0 then + crossfireTelemetryPush(0x2C, { deviceId, handsetId, loadQ[#loadQ], fieldChunk }) + fieldTimeout = time + 50 -- 0.5s + end + end + + if time > titleShowWarnTimeout then + -- if elrsFlags bit set is bit higher than bit 0 and bit 1, it is warning flags + titleShowWarn = (elrsFlags > 3 and not titleShowWarn) or nil + titleShowWarnTimeout = time + 100 + end +end + +local lcd_title -- holds function that is color/bw version +local function lcd_title_color() + lcd.clear() + + local EBLUE = lcd.RGB(0x43, 0x61, 0xAA) + local EGREEN = lcd.RGB(0x9f, 0xc7, 0x6f) + local EGREY1 = lcd.RGB(0x91, 0xb2, 0xc9) + local EGREY2 = lcd.RGB(0x6f, 0x62, 0x7f) + local barHeight = 30 + + -- Field display area (white w/ 2px green border) + lcd.setColor(CUSTOM_COLOR, EGREEN) + lcd.drawRectangle(0, 0, LCD_W, LCD_H, CUSTOM_COLOR) + lcd.drawRectangle(1, 0, LCD_W - 2, LCD_H - 1, CUSTOM_COLOR) + -- title bar + lcd.drawFilledRectangle(0, 0, LCD_W, barHeight, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR, EGREY1) + lcd.drawFilledRectangle(LCD_W - textSize, 0, textSize, barHeight, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR, EGREY2) + lcd.drawRectangle(LCD_W - textSize, 0, textSize, barHeight - 1, CUSTOM_COLOR) + lcd.drawRectangle(LCD_W - textSize, 1 , textSize - 1, barHeight - 2, CUSTOM_COLOR) -- left and bottom line only 1px, make it look bevelled + lcd.setColor(CUSTOM_COLOR, BLACK) + if titleShowWarn then + lcd.drawText(textXoffset + 1, 4, elrsFlagsInfo, CUSTOM_COLOR) + lcd.drawText(LCD_W - textSize - 5, 4, tostring(elrsFlags), RIGHT + BOLD + CUSTOM_COLOR) + else + local title = fields_count > 0 and deviceName or "Loading..." + lcd.drawText(textXoffset + 1, 4, title, CUSTOM_COLOR) + lcd.drawText(LCD_W - 5, 4, goodBadPkt, RIGHT + BOLD + CUSTOM_COLOR) + end + -- progress bar + if #loadQ > 0 and fields_count > 0 then + local barW = (COL2-4) * (fields_count - #loadQ) / fields_count + lcd.setColor(CUSTOM_COLOR, EBLUE) + lcd.drawFilledRectangle(2, 2+20, barW, barHeight-5-20, CUSTOM_COLOR) + lcd.setColor(CUSTOM_COLOR, WHITE) + lcd.drawFilledRectangle(2+barW, 2+20, COL2-2-barW, barHeight-5-20, CUSTOM_COLOR) + end +end + +local function lcd_title_bw() + lcd.clear() + -- B&W screen + local barHeight = 9 + if titleShowWarn then + lcd.drawText(LCD_W, 1, tostring(elrsFlags), RIGHT) + else + lcd.drawText(LCD_W - 1, 1, goodBadPkt, RIGHT) + lcd.drawLine(LCD_W - 10, 0, LCD_W - 10, barHeight-1, SOLID, INVERS) + end + + if #loadQ > 0 and fields_count > 0 then + lcd.drawFilledRectangle(COL2, 0, LCD_W, barHeight, GREY_DEFAULT) + lcd.drawGauge(0, 0, COL2, barHeight, fields_count - #loadQ, fields_count, 0) + else + lcd.drawFilledRectangle(0, 0, LCD_W, barHeight, GREY_DEFAULT) + if titleShowWarn then + lcd.drawText(textXoffset, 1, elrsFlagsInfo, INVERS) + else + local title = fields_count > 0 and deviceName or "Loading..." + lcd.drawText(textXoffset, 1, title, INVERS) + end + end +end + +local function lcd_warn() + lcd.drawText(textXoffset, textSize*2, "Error:") + lcd.drawText(textXoffset, textSize*3, elrsFlagsInfo) + lcd.drawText(LCD_W/2, textSize*5, "[OK]", BLINK + INVERS + CENTER) +end + +local function reloadCurField() + local field = getField(lineIndex) + fieldTimeout = 0 + fieldChunk = 0 + fieldData = {} + loadQ[#loadQ+1] = field.id +end + +local function reloadRelatedFields(field) + -- Reload the parent folder to update the description + if field.parent then + loadQ[#loadQ+1] = field.parent + fields[field.parent].name = nil + end + + -- Reload all editable fields at the same level as well as the parent item + for fieldId = fields_count, 1, -1 do + -- Skip this field, will be added to end + local fldTest = fields[fieldId] + if fieldId ~= field.id + and fldTest.parent == field.parent + and (fldTest.type or 99) < 11 then -- type could be nil if still loading + fldTest.nc = true -- "no cache" the options + loadQ[#loadQ+1] = fieldId + end + end + + -- Reload this field + loadQ[#loadQ+1] = field.id + -- with a short delay to allow the module EEPROM to commit + fieldTimeout = getTime() + 20 +end + +local function handleDevicePageEvent(event) + if #fields == 0 then --if there is no field yet + return + else + if fields[backButtonId].name == nil then --if back button is not assigned yet, means there is no field yet. + return + end + end + + if event == EVT_VIRTUAL_EXIT then -- Cancel edit / go up a folder / reload all + if edit then + edit = nil + reloadCurField(0) + else + if folderAccess == nil and #loadQ == 0 then -- only do reload if we're in the root folder and finished loading + if deviceId ~= 0xEE then + changeDeviceId(0xEE) --change device id clear the fields_count, therefore the next ping will do reloadAllField() + else + reloadAllField() + end + crossfireTelemetryPush(0x28, { 0x00, 0xEA }) + end + UIbackExec() + end + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field + if elrsFlags > 0x1F then + elrsFlags = 0 + crossfireTelemetryPush(0x2D, { deviceId, handsetId, 0x2E, 0x00 }) + else + local field = getField(lineIndex) + if field and field.name then + if field.type < 10 then + edit = not edit + end + if not edit then + if field.type < 10 then + -- Editable fields + reloadRelatedFields(field) + elseif field.type == 13 then + -- Command + reloadCurField() + end + if functions[field.type+1].save then + functions[field.type+1].save(field) + end + end + end + end + elseif edit then + if event == EVT_VIRTUAL_NEXT then + incrField(1) + elseif event == EVT_VIRTUAL_PREV then + incrField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREV then + selectField(-1) + end + end +end + +-- Main +local function runDevicePage(event) + handleDevicePageEvent(event) + + lcd_title() + + if #devices > 1 then -- show other device folder + fields[fields_count+1].parent = nil + end + if elrsFlags > 0x1F then + lcd_warn() + else + for y = 1, maxLineIndex+1 do + local field = getField(pageOffset+y) + if not field then + break + elseif field.name ~= nil then + local attr = lineIndex == (pageOffset+y) + and ((edit and BLINK or 0) + INVERS) + or 0 + if field.type < 11 or field.type == 12 then -- if not folder, command, or back + lcd.drawText(textXoffset, y*textSize+textYoffset, field.name, 0) + end + if functions[field.type+1].display then + functions[field.type+1].display(field, y*textSize+textYoffset, attr) + end + end + end + end +end + +local function popupCompat(t, m, e) + -- Only use 2 of 3 arguments for older platforms + return popupConfirmation(t, e) +end + +local function runPopupPage(event) + if event == EVT_VIRTUAL_EXIT then + crossfireTelemetryPush(0x2D, { deviceId, handsetId, fieldPopup.id, 5 }) -- lcsCancel + fieldTimeout = getTime() + 200 -- 2s + end + + local result + if fieldPopup.status == 0 and fieldPopup.lastStatus ~= 0 then -- stopped + popupCompat(fieldPopup.info, "Stopped!", event) + reloadAllField() + fieldPopup = nil + elseif fieldPopup.status == 3 then -- confirmation required + result = popupCompat(fieldPopup.info, "PRESS [OK] to confirm", event) + fieldPopup.lastStatus = fieldPopup.status + if result == "OK" then + crossfireTelemetryPush(0x2D, { deviceId, handsetId, fieldPopup.id, 4 }) -- lcsConfirmed + fieldTimeout = getTime() + fieldPopup.timeout -- we are expecting an immediate response + fieldPopup.status = 4 + elseif result == "CANCEL" then + fieldPopup = nil + end + elseif fieldPopup.status == 2 then -- running + if fieldChunk == 0 then + commandRunningIndicator = (commandRunningIndicator % 4) + 1 + end + result = popupCompat(fieldPopup.info .. " [" .. string.sub("|/-\\", commandRunningIndicator, commandRunningIndicator) .. "]", "Press [RTN] to exit", event) + fieldPopup.lastStatus = fieldPopup.status + if result == "CANCEL" then + crossfireTelemetryPush(0x2D, { deviceId, handsetId, fieldPopup.id, 5 }) -- lcsCancel + fieldTimeout = getTime() + fieldPopup.timeout -- we are expecting an immediate response + fieldPopup = nil + end + end +end + +local function loadSymbolChars() + -- On firmwares that have constants defined for the arrow chars, use them in place of + -- the \xc0 \xc1 chars (which are OpenTX-en) + if __opentx then + byteToStr = function (b) + -- Use the table to convert the char, else use string.char if not in the table + return ({ + [192] = __opentx.CHAR_UP, + [193] = __opentx.CHAR_DOWN + })[b] or string.char(b) + end + else + byteToStr = string.char + end +end + +local function touch2evt(event, touchState) + -- Convert swipe events to normal events Left/Right/Up/Down -> EXIT/ENTER/PREV/NEXT + -- PREV/NEXT are swapped if editing + -- TAP is converted to ENTER + touchState = touchState or {} + return (touchState.swipeLeft and EVT_VIRTUAL_EXIT) + or (touchState.swipeRight and EVT_VIRTUAL_ENTER) + or (touchState.swipeUp and (edit and EVT_VIRTUAL_NEXT or EVT_VIRTUAL_PREV)) + or (touchState.swipeDown and (edit and EVT_VIRTUAL_PREV or EVT_VIRTUAL_NEXT)) + or (event == EVT_TOUCH_TAP and EVT_VIRTUAL_ENTER) +end + +local function setLCDvar() + -- Set the title function depending on if LCD is color, and free the other function and + -- set textselection unit function, use GetLastPost or sizeText + if (lcd.RGB ~= nil) then + lcd_title = lcd_title_color + functions[10].display=fieldTextSelectionDisplay_color + else + lcd_title = lcd_title_bw + functions[10].display=fieldTextSelectionDisplay_bw + touch2evt = nil + end + lcd_title_color = nil + lcd_title_bw = nil + fieldTextSelectionDisplay_bw = nil + fieldTextSelectionDisplay_color = nil + -- Determine if popupConfirmation takes 3 arguments or 2 + -- if pcall(popupConfirmation, "", "", EVT_VIRTUAL_EXIT) then + -- major 1 is assumed to be FreedomTX + local ver, radio, major = getVersion() + if major ~= 1 then + popupCompat = popupConfirmation + end + if LCD_W == 480 then + COL2 = 240 + maxLineIndex = 10 + textXoffset = 3 + textYoffset = 10 + textSize = 22 --textSize is text Height + elseif LCD_W == 320 then + COL2 = 160 + maxLineIndex = 14 + textXoffset = 3 + textYoffset = 10 + textSize = 22 + else + if LCD_W == 212 then + COL2 = 110 + else + COL2 = 70 + end + maxLineIndex = 6 + textXoffset = 0 + textYoffset = 3 + textSize = 8 + end + loadSymbolChars() + loadSymbolChars = nil +end + +local function setMock() + -- Setup fields to display if running in Simulator + local _, rv = getVersion() + if string.sub(rv, -5) ~= "-simu" then return end + local mock = loadScript("mockup/elrsmock.lua") + if mock == nil then return end + fields, goodBadPkt, deviceName = mock(), "0/500 C", "ExpressLRS TX" + fields_count = #fields - 1 + loadQ = { fields_count } + deviceIsELRS_TX = true + backButtonId = #fields + + fields_count = fields_count + 1 + exitButtonId = fields_count + 1 + fields[exitButtonId] = {id = exitButtonId, name="----EXIT----", type=17} +end + +-- Init +local function init() + setLCDvar() + setMock() + setLCDvar = nil + setMock = nil +end + +-- Main +local function run(event, touchState) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + event = (touch2evt and touch2evt(event, touchState)) or event + if fieldPopup ~= nil then + runPopupPage(event) + else + runDevicePage(event) + end + + refreshNext() + + return exitscript +end + +return { init=init, run=run } diff --git a/SCRIPTS/TOOLS/elrsV3.luac b/SCRIPTS/TOOLS/elrsV3.luac new file mode 100755 index 0000000..e4dc213 Binary files /dev/null and b/SCRIPTS/TOOLS/elrsV3.luac differ diff --git a/SCRIPTS/TOOLS/pidDsm.lua b/SCRIPTS/TOOLS/pidDsm.lua new file mode 100644 index 0000000..8d2b89b --- /dev/null +++ b/SCRIPTS/TOOLS/pidDsm.lua @@ -0,0 +1,127 @@ +-- +-- This telemetry script displays the Flight Log Gain +-- Parameters streamed from the Blade 150S Spektrum AR6335A +-- Flybarless Controller. + +-- The script facilitates the setting of the FBL's +-- Gain Parameters including PID for both +-- cyclic and tail. It is similar to the Telemetry Based +-- Text Generator available on Spektrum transmitters. + +-- Supporting similar Blade micros such as the Fusion 180 +-- would possibly require minor modifications to this script. + +-- This script reads telemetry data from the Spektrum +-- receiver and thus functionality relies on data being +-- captured by the OpenTX transmitter. A DSM +-- telemetry-ready module is required. Please see the +-- MULTI-Module project at https://www.multi-module.org/. + +-- The only supported display is the Taranis'. It may work +-- with higher res screens. +-- + + +-- Sensor names +local PSensor = "FdeA" +local ISensor = "FdeB" +local DSensor = "FdeL" +local RSensor = "FdeR" +local ActiveParamSensor = "Hold" + +local tags = {"P", "I", "D"} + + +local function getPage(iParam) + -- get page from 0-based index + -- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2) + local res = (math.floor(iParam/4)==0) and 1 or 2 + return res +end + +function round(v) + -- round float + local factor = 100 + return math.floor(v * factor + 0.5) / factor +end + + +local function readValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + v = round(v) + return v +end + +local function readActiveParamValue(sensor) + -- read and return a validated active parameter value + local v = getValue(sensor) + if (v<1 or v>8) then + return nil + end + return v +end + +local function readParameters() + -- read and return parameters + local p = readValue(PSensor) + local i = readValue(ISensor) + local d = readValue(DSensor) + local r = readValue(RSensor) + local a = readActiveParamValue(ActiveParamSensor) + return {p,i,d,r,a} +end + +local function drawParameters() + -- draw labels and params on screen + local params = readParameters() + local activeParam = params[5] + + -- if active gain does not validate then assume + -- Gain Adjustment Mode is disabled + if not activeParam then + lcd.clear() + lcd.drawText(20,30,"Please enter Gain Adjustment Mode") + return + end + + local activePage = getPage(activeParam-1) + for iParam=0,7 do + -- highlight selected parameter + local attr = (activeParam==iParam+1) and 2 or 0 + -- circular index (per page) + local perPageIndx = iParam % 4 + 1 + -- check if displaying cyclic params. + local isCyclicPage = (getPage(iParam)==1) + -- set y draw coord + local y = perPageIndx*10+2 + + -- labels + local x = isCyclicPage and 6 or 120 + -- labels are P,I,D for both pages except for last param + local val = iParam==3 and "Response" or + (iParam==7 and "Filtering" or tags[perPageIndx]) + lcd.drawText (x, y, val, attr) + + -- gains + -- set all params for non-active page to '--' rather than 'last value' + val = (getPage(iParam)==activePage) and params[perPageIndx] or '--' + x = isCyclicPage and 70 or 180 + lcd.drawText (x, y, val, attr) + end +end + + +local function run_func(event) + -- TODO: calling clear() on every function call redrawing all labels is not ideal + lcd.clear() + lcd.drawText (8, 2, "Cyclic (0...200)") + lcd.drawText (114, 2, "Tail (0...200)") + drawParameters() +end + +local function init_func() end +local function bg_func() end + + +return { run=run_func, background=bg_func, init=init_func } diff --git a/SCRIPTS/TOOLS/readme.txt b/SCRIPTS/TOOLS/readme.txt new file mode 100755 index 0000000..9ea1e7c --- /dev/null +++ b/SCRIPTS/TOOLS/readme.txt @@ -0,0 +1 @@ +Scripts that need to be available in TOOLS menu should be in this directory. diff --git a/SCRIPTS/WIZARD/delta.lua b/SCRIPTS/WIZARD/delta.lua new file mode 100755 index 0000000..fd0d7d5 --- /dev/null +++ b/SCRIPTS/WIZARD/delta.lua @@ -0,0 +1,383 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### +-- Delta Wizard pages +local ENGINE_PAGE = 0 +local ELEVONS_PAGE = 1 +local RUDDER_PAGE = 2 +local CONFIRMATION_PAGE = 3 + +-- Navigation variables +local page = ENGINE_PAGE +local dirty = true +local edit = false +local field = 0 +local fieldsMax = 0 + +-- Model settings +local engineMode = 1 +local thrCH1 = 0 +local elevCH1 = 0 +local elevCH2 = 0 +local elevonsMode = 0 +local rudderMode = 0 +local rudCH1 = 0 +local servoPage = nil + +-- Common functions +local lastBlink = 0 +local function blinkChanged() + local time = getTime() % 128 + local blink = (time - time % 64) / 64 + if blink ~= lastBlink then + lastBlink = blink + return true + else + return false + end +end + +local function fieldIncDec(event, value, max, force) + if edit or force==true then + if event == EVT_VIRTUAL_INC then + value = (value + max) + dirty = true + elseif event == EVT_VIRTUAL_DEC then + value = (value + max + 2) + dirty = true + end + value = (value % (max+1)) + end + return value +end + +local function valueIncDec(event, value, min, max) + if edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + if value < max then + value = (value + 1) + dirty = true + end + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + if value > min then + value = (value - 1) + dirty = true + end + end + end + return value +end + +local function navigate(event, fieldMax, prevPage, nextPage) + if event == EVT_VIRTUAL_ENTER then + edit = not edit + dirty = true + elseif edit then + if event == EVT_VIRTUAL_EXIT then + edit = false + dirty = true + elseif not dirty then + dirty = blinkChanged() + end + else + if event == EVT_VIRTUAL_NEXT_PAGE then + page = nextPage + field = 0 + dirty = true + elseif event == EVT_VIRTUAL_PREV_PAGE then + page = prevPage + field = 0 + killEvents(event); + dirty = true + else + field = fieldIncDec(event, field, fieldMax, true) + end + end +end + +local function getFieldFlags(position) + flags = 0 + if field == position then + flags = INVERS + if edit then + flags = INVERS + BLINK + end + end + return flags +end + +local function channelIncDec(event, value) + if not edit and event==EVT_VIRTUAL_MENU then + servoPage = value + dirty = true + else + value = valueIncDec(event, value, 0, 15) + end + return value +end + +-- Init function +local function init() + rudCH1 = defaultChannel(0) + thrCH1 = defaultChannel(2) + elevCH1 = defaultChannel(1) + elevCH2 = defaultChannel(3) +end + +-- Engine Menu +local engineModeItems = {"No", "Yes"} +local function drawEngineMenu() + lcd.clear() + if engineMode == 0 then + -- No engine + fieldsMax = 0 + else + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+thrCH1, getFieldFlags(1)) + fieldsMax = 1 + end + lcd.drawText(1, 0, "Got an engine?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, engineModeItems, engineMode, getFieldFlags(0)) +end + +local function engineMenu(event) + if dirty then + dirty = false + drawEngineMenu() + end + + navigate(event, fieldsMax, page, page+1) + + if field==0 then + engineMode = fieldIncDec(event, engineMode, 1) + elseif field==1 then + thrCH1 = channelIncDec(event, thrCH1) + end +end + +-- Elevons Menu +local elevonsModeItems = {"2 Channels"} +local function drawElevonsMenu() + lcd.clear() + lcd.drawText(1, 0, "Select elevon channnels", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, elevonsModeItems, elevonsMode, 0) + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(30, 40, "L", 0); + lcd.drawText(65, 40, "R", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+elevCH1, getFieldFlags(0)) + lcd.drawSource(60, 50, MIXSRC_CH1+elevCH2, getFieldFlags(1)) + fieldsMax = 1 +end + +local function elevonsMenu(event) + if dirty then + dirty = false + drawElevonsMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + elevCH1 = channelIncDec(event, elevCH1) + elseif field==1 then + elevCH2 = channelIncDec(event, elevCH2) + end +end + +-- Rudder menu +local rudderModeItems = {"No", "Yes"} + +local function drawRudderMenu() + lcd.clear() + if rudderMode == 0 then + -- No rudder + fieldsMax = 0 + else + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+rudCH1, getFieldFlags(1)) + fieldsMax = 1 + end + lcd.drawText(1, 0, "Got a rudder?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, rudderModeItems, rudderMode, getFieldFlags(0)) +end + +local function rudderMenu(event) + if dirty then + dirty = false + drawRudderMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + rudderMode = fieldIncDec(event, rudderMode, 1) + elseif field==1 then + rudCH1 = channelIncDec(event, rudCH1) + end +end + +-- Servo (limits) Menu +local function drawServoMenu(limits) + lcd.clear() + lcd.drawSource(1, 0, MIXSRC_CH1+servoPage, 0) + lcd.drawText(25, 0, "servo min/max/center/direction?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawNumber(140, 35, limits.min, PREC1+getFieldFlags(0)); + lcd.drawNumber(205, 35, limits.max, PREC1+getFieldFlags(1)); + lcd.drawNumber(170, 9, limits.offset, PREC1+getFieldFlags(2)); + if limits.revert == 0 then + lcd.drawText(129, 50, "\126", getFieldFlags(3)); + else + lcd.drawText(129, 50, "\127", getFieldFlags(3)); + end + fieldsMax = 3 +end + +local function servoMenu(event) + local limits = model.getOutput(servoPage) + + if dirty then + dirty = false + drawServoMenu(limits) + end + + navigate(event, fieldsMax, page, page) + + if edit then + if field==0 then + limits.min = valueIncDec(event, limits.min, -1000, 0) + elseif field==1 then + limits.max = valueIncDec(event, limits.max, 0, 1000) + elseif field==2 then + limits.offset = valueIncDec(event, limits.offset, -1000, 1000) + elseif field==3 then + limits.revert = fieldIncDec(event, limits.revert, 1) + end + model.setOutput(servoPage, limits) + elseif event == EVT_VIRTUAL_EXIT then + servoPage = nil + dirty = true + end +end + +-- Confirmation Menu +local function addMix(channel, input, name, weight, index) + local mix = { source=input, name=name } + if weight ~= nil then + mix.weight = weight + end + if index == nil then + index = 0 + end + model.insertMix(channel, index, mix) +end + +local function applySettings() + model.defaultInputs() + model.deleteMixes() + if engineMode == 1 then + addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Engine") + end + addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "D-EleL", 50) + addMix(elevCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "D-AilL", 50, 1) + addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(1), "D-EleR", 50) + addMix(elevCH2, MIXSRC_FIRST_INPUT+defaultChannel(3), "D-AilR", -50, 1) + if rudderMode == 1 then + addMix(rudCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Rudder") + end +end + +local function drawNextLine(x, y, label, channel) + lcd.drawText(x, y, label, 0); + lcd.drawText(x+48, y, ":", 0); + lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0) + y = y + 8 + if y > 50 then + y = 12 + x = 120 + end + return x, y +end + +local function drawConfirmationMenu() + local x = 22 + local y = 12 + lcd.clear() + lcd.drawText(48, 1, "Ready to go?", 0); + lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0) + if engineMode == 1 then + x, y = drawNextLine(x, y, "Throttle", thrCH1) + end + x, y = drawNextLine(x, y, "Elevon L", elevCH1) + x, y = drawNextLine(x, y, "Elevon R", elevCH2) + if rudderMode == 1 then + drawNextLine(x, y, "Rudder", rudCH1) + end + lcd.drawText(0, LCD_H-8, "[Enter Long] to confirm", 0); + lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0) + fieldsMax = 0 +end + +local function confirmationMenu(event) + if dirty then + dirty = false + drawConfirmationMenu() + end + + navigate(event, fieldsMax, RUDDER_PAGE, page) + + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_ENTER_LONG then + killEvents(event) + applySettings() + return 2 + else + return 0 + end +end + +-- Main + +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + end + + if servoPage ~= nil then + servoMenu(event) + elseif page == ENGINE_PAGE then + engineMenu(event) + elseif page == ELEVONS_PAGE then + elevonsMenu(event) + elseif page == RUDDER_PAGE then + rudderMenu(event) + elseif page == CONFIRMATION_PAGE then + return confirmationMenu(event) + end + return 0 +end + +return { init=init, run=run } diff --git a/SCRIPTS/WIZARD/heli.lua b/SCRIPTS/WIZARD/heli.lua new file mode 100755 index 0000000..4545da3 --- /dev/null +++ b/SCRIPTS/WIZARD/heli.lua @@ -0,0 +1,533 @@ +---- ######################################################################### +---- # # +---- # 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 VALUE = 0 +local COMBO = 1 +local edit = false +local page = 1 +local current = 1 +local pages = {} +local fields = {} +local switches = {"SA", "SB", "SC", "SD", "SF"} +local switchValues = {[0]=2, 5, 8, 11, 14} + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[3] == VALUE then + min = field[6] + max = field[7] + elseif field[3] == COMBO then + min = 0 + max = #(field[6]) - 1 + end + if (step < 0 and field[5] > min) or (step > 0 and field[5] < max) then + field[5] = field[5] + step + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + edit = false + current = 1 +end + +-- Select the next or previous editable field +local function selectField(step) + repeat + current = 1 + ((current + step - 1 + #fields) % #fields) + until fields[current][4]==1 +end + +-- Redraw the current page +local function redrawFieldsPage(event) + + for index = 1, 10, 1 do + local field = fields[index] + if field == nil then + break + end + + local attr = current == (index) and ((edit == true and BLINK or 0) + INVERS) or 0 + attr = attr + + if field[4] == 1 then + if field[3] == VALUE then + lcd.drawNumber(field[1], field[2], field[5], LEFT + attr) + elseif field[3] == COMBO then + if field[5] >= 0 and field[5] < #(field[6]) then + lcd.drawText(field[1],field[2], field[6][1+field[5]], attr) + end + end + end + end +end + +local function updateField(field) + local value = field[5] +end + +-- Main +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then -- exit script + return 2 + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field + if fields[current][5] ~= nil then + edit = not edit + if edit == false then + lcd.clear() + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + addField(1) + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREV then + selectField(-1) + end + end + redrawFieldsPage(event) + return 0 +end + +-- set visibility flags starting with SECOND field of fields +local function setFieldsVisible(...) + local arg={...} + local cnt = 2 + for i,v in ipairs(arg) do + fields[cnt][4] = v + cnt = cnt + 1 + end +end + +local TypeFields = { + {0, 12, COMBO, 1, 0, {"Flybarless (FBL)", "Flybarred (FB)" } }, + {65, 25, COMBO, 1, 0, {"120", "120X", "140", "90" } }, +} + +local function runTypeConfig(event) + lcd.clear() + fields = TypeFields + lcd.drawScreenTitle("Helicopter Type", 1,9) + fields[2][4] = 0 + if fields[1][5] == 1 then + lcd.drawText(0, 25, "Swash Type") + fields[2][4] = 1 + end + local result = runFieldsPage(event) + return result +end + +local StyleFields = { + {0, 12, COMBO, 1, 0, { "Sport", "Light 3D","Full 3D" } }, +} + +local function runStyleConfig(event) + lcd.clear() + fields = StyleFields + lcd.drawScreenTitle("Your Flying Style",2,9) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local SwitchFields = { + {75, 12, COMBO, 1, 0, { "SA", "SB", "SC", "SD","SF" } }, + {75, 33, COMBO, 1, 4, { "SA", "SB", "SC", "SD","SF" } }, + {75, 54, COMBO, 1, 2, { "SA", "SB", "SC", "SD", "SF" } }, +} + +local function runSwitchConfig(event) + lcd.clear() + lcd.drawScreenTitle("Assign Switches",3,9) + fields = SwitchFields + lcd.drawText(0, 12, "FM (Idle Up)") + fields[1][4]=1 + lcd.drawText(0, 33, "Throttle Hold") + fields[2][4]=1 + fields[3][4]=0 + if TypeFields[1][5]==1 then + lcd.drawText(0, 54, "Tail Gain") + fields[3][4]=1 + end + local result = runFieldsPage(event) + return result +end + +local ThrFields = { + {0, 12, COMBO, 1, 2, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local function runThrConfig(event) + lcd.clear() + fields = ThrFields + lcd.drawScreenTitle("Throttle Channel",3,9) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local CurveFields = { + {75, 12, COMBO, 1, 0, { "Thr Up", "V Curve","Flat" } }, + {75, 32, COMBO, 1, 0, { "V Curve","Flat" } }, + {75, 54, COMBO, 1, 0, { "V Curve","Flat" } }, +} + +local function runCurveConfig(event) + lcd.clear() + fields = CurveFields + lcd.drawScreenTitle("FM Throttle Curves",4,9) + lcd.drawText(0, 12, "FM0 Curve") + fields[1][4]=1 + lcd.drawText(0, 32, "FM1 Curve") + fields[2][4]=1 + lcd.drawText(0, 54, "FM2 Curve") + fields[3][4]=1 + local result = runFieldsPage(event) + return result +end + +local AilerFields = { + {0, 12, COMBO, 1, 0, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local function runAilerConfig(event) + lcd.clear() + fields = AilerFields + lcd.drawScreenTitle("Aileron Channel",5,9) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local EleFields = { + {0, 12, COMBO, 1, 1, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local function runEleConfig(event) + lcd.clear() + fields = EleFields + lcd.drawScreenTitle("Elevator Channel",6,9) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local RudFields = { + {0, 12, COMBO, 1, 3, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local function runRudConfig(event) + lcd.clear() + fields = RudFields + lcd.drawScreenTitle("Rudder (Tail) Channel",7,9) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local lineIndex + +local function drawNextChanelLine(text, text2) + lcd.drawText(0, lineIndex, text) + lcd.drawText(55, lineIndex, ": CH" .. text2 + 1) + lineIndex = lineIndex + 9 +end + +local function drawNextSwitchLine(text, text2) + lcd.drawText(0, lineIndex, text) + lcd.drawText(55, lineIndex, ": " ..switches[text2 + 1]) + lineIndex = lineIndex + 9 +end + +local function drawNextTextLine(text, text2) + lcd.drawText(0, lineIndex, text) + lcd.drawText(55, lineIndex, ": " ..text2) + lineIndex = lineIndex + 9 +end + +local function switchLine(text) + text=SwitchFields[2][5] + getFieldInfo(text) + swnum=text.id +end + +local SummaryFields = { + {0, 56, {1}}, +} + +local function runSummary(event) + lcd.clear() + lcd.drawScreenTitle("Summary", 8,9) + fields = SummaryFields + lineIndex = 9 + + -- Type + if TypeFields[1][5]==0 then + drawNextTextLine("TYPE","FBL") + else + drawNextTextLine("TYPE","FB") + if TypeFields[2][5]==0 then + lcd.drawText(75,9,"120") + elseif TypeFields[2][5]==1 then + lcd.drawText(75,9,"120X") + elseif TypeFields[2][5]==2 then + lcd.drawText(75,9,"140") + else + lcd.drawText(75,9,"90") + end + end + + -- Style + if StyleFields[1][5]==0 then + drawNextTextLine("Style","Sport") + elseif StyleFields[1][5]==1 then + drawNextTextLine("Style","Light 3D") + else + drawNextTextLine("Style","Full 3D") + end + + -- Switch + drawNextSwitchLine("FM SW",SwitchFields[1][5]) + drawNextSwitchLine("Th Hold SW",SwitchFields[2][5]) + if TypeFields[1][5]==1 then + drawNextSwitchLine("Gyro SW",SwitchFields[3][5]) + end + + -- thr + drawNextChanelLine("Throttle",ThrFields[1][5]) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local ConfigSummaryFields = { + {10, 50,{1}}, +} + +local function runConfigSummary(event) + lcd.clear() + lcd.drawScreenTitle("Long Enter -> Create", 9,9) + fields = ConfigSummaryFields + lineIndex = 8 + + -- FM0 Curve + if CurveFields[1][5]==0 then + drawNextTextLine("FM0 Curve","Throttle Up") + elseif CurveFields[1][5]==1 then + drawNextTextLine("FM0 Curve","V Style") + else + drawNextTextLine("FM0 Curve","Flat Style") + end + + -- FM1 Curve + if CurveFields[2][5]==0 then + drawNextTextLine("FM1 Curve","V Style") + else + drawNextTextLine("FM1 Curve","Flat Style") + end + + -- FM3 Curve + if CurveFields[3][5]==0 then + drawNextTextLine("FM2 Curve","V Style") + else + drawNextTextLine("FM2 Curve","Flat Style") + end + + -- Ail + drawNextChanelLine("Aileron",AilerFields[1][5]) + + -- Elev + drawNextChanelLine("Elevator",EleFields[1][5]) + + -- Rudder + drawNextChanelLine("Rudder",RudFields[1][5]) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local function runCreateModel(event) + lcd.clear() + local b = SwitchFields[1][5] + local tUp = switchValues[b] + local i = SwitchFields[2][5] + local hold = switchValues[i] + local f = SwitchFields[3][5] + local gyRate = switchValues[f] + model.defaultInputs() + model.deleteMixes() + + -- Curve Fm0 + if StyleFields[1][5]==0 and CurveFields[1][5]==0 then + model.setCurve(0,{name="TC0",y={-100, 0, 0, 40, 40}}) + elseif StyleFields[1][5]==1 and CurveFields[1][5]==0 then + model.setCurve(0,{name="TC0",y={-100, 0, 35, 50, 50}}) + elseif StyleFields[1][5]==2 and CurveFields[1][5]==0 then + model.setCurve(0,{name="TC0",y={-100, 0, 40, 80, 80}}) + elseif StyleFields[1][5]==0 and CurveFields[1][5]==1 then + model.setCurve(0,{name="TC0",y={50, 40, 50}}) + elseif StyleFields[1][5]==1 and CurveFields[1][5]==1 then + model.setCurve(0,{name="TC0",y={65, 55, 65}}) + elseif StyleFields[1][5]==2 and CurveFields[1][5]==1 then + model.setCurve(0,{name="TC0",y={70, 60, 70}}) + elseif StyleFields[1][5]==0 and CurveFields[1][5]==2 then + model.setCurve(0,{name="TC0",y={60,60,60}}) + elseif StyleFields[1][5]==1 and CurveFields[1][5]==2 then + model.setCurve(0,{name="TC0",y={65,65,65}}) + else + model.setCurve(0,{name="TC0",y={70,70,70}}) + end + + --Curve FM1 + if StyleFields[1][5]==0 and CurveFields[2][5]==0 then + model.setCurve(1,{name="TC1",y={60, 50, 60}}) + elseif StyleFields[1][5]==1 and CurveFields[2][5]==0 then + model.setCurve(1,{name="TC1",y={70, 60, 70}}) + elseif StyleFields[1][5]==2 and CurveFields[2][5]==0 then + model.setCurve(1,{name="TC1",y={85, 75, 85}}) + elseif StyleFields[1][5]==0 and CurveFields[2][5]==1 then + model.setCurve(1,{name="TC1",y={65,65,65}}) + elseif StyleFields[1][5]==1 and CurveFields[2][5]==1 then + model.setCurve(1,{name="TC1",y={70,70,70}}) + else + model.setCurve(1,{name="TC1",y={85 ,85,85}}) + end + + --Curve FM2 + if StyleFields[1][5]>=0 and CurveFields[3][5]==0 then + model.setCurve(2,{name="TC2",y={70, 60, 70}}) + elseif StyleFields[1][5]==1 and CurveFields[3][5]==0 then + model.setCurve(2,{name="TC2",y={85, 70, 85}}) + elseif StyleFields[1][5]==2 and CurveFields[3][5]==0 then + model.setCurve(2,{name="TC2",y={100, 90, 100}}) + elseif StyleFields[1][5]==0 and CurveFields[3][5]==1 then + model.setCurve(2,{name="TC2",y={75 ,75,75}}) + elseif StyleFields[1][5]==1 and CurveFields[3][5]==1 then + model.setCurve(2,{name="TC2",y={85 ,85, 85}}) + else + model.setCurve(2,{name="TC2",y={95 ,95, 95}}) + end + + --Curve TH Hold + model.setCurve(3,{name="THD",y={-100,-100,-100}}) + + -- Throttle + model.insertMix(ThrFields[1][5], 0,{name="Th0",weight=100,curveType=3,curveValue=1}) + model.insertMix(ThrFields[1][5], 1,{name="Th1",weight=100,switch=tUp,multiplex=2,curveType=3,curveValue=2}) + model.insertMix(ThrFields[1][5], 2,{name="Th2",weight=100,switch=tUp-1,multiplex=2,curveType=3,curveValue=3}) + model.insertMix(ThrFields[1][5], 3,{name="Hld",weight=100,offset=-15,switch=hold+1,multiplex=2,curveType=3,curveValue=4}) + model.setOutput(ThrFields[1][5],{name="Thrt"}) + + -- Ail + if TypeFields[1][5] == 0 then + model.insertMix(AilerFields[1][5], 0,{name="Ail",weight=100}) + model.setOutput(AilerFields[1][5],{name="Aile"}) + else + model.insertMix(AilerFields[1][5], 0,{source=83,name="Ail",weight=100}) + model.setOutput(AilerFields[1][5],{name="Aile"}) + end + + -- Elev + if TypeFields[1][5] == 0 then + model.insertMix(EleFields[1][5], 0,{name="Ele",weight=100}) + model.setOutput(EleFields[1][5],{name="Elev"}) + else + model.insertMix(EleFields[1][5], 0,{source=82,name="Ele",weight=100}) + model.setOutput(EleFields[1][5],{name="Elev"}) + end + + -- Rudder + model.insertMix(RudFields[1][5], 0,{name="Rud",weight=100}) + model.setOutput(RudFields[1][5],{name="Rud"}) + + -- Gyro + if TypeFields[1][5] == 0 then + model.insertMix(4, 0,{source=81,name="T.Ga",weight=25}) + model.setOutput(4,{name="T.Ga"}) + else + model.insertMix( 4, 0,{source=81,name="HHold",weight=25}) + model.insertMix( 4, 1,{source=81,name="Rate",weight=-25,switch=gyRate,multiplex=2}) + model.setOutput(4,{name="T.Ga"}) + end + + -- Pitch + if TypeFields[1][5] == 0 then + model.insertMix(5, 0,{source=77,name="Pch",weight=100}) + model.setOutput(5,{name="Ptch"}) + else + model.insertMix(5, 0,{source=84,name="Pch",weight=100}) + model.setOutput(5,{name="Ptch"}) + end + + --Set Swash Parameters + if TypeFields[1][5]==1 and TypeFields[2][5]==0 then + model.setSwashRing({type="1",collectiveSource=77,aileronSource=78,elevatorSource=76,collectiveWeight=60,aileronWeight=60,elevatorWeight=60}) + elseif TypeFields[2][5]==1 then + model.setSwashRing({type="2",collectiveSource=77,aileronSource=78,elevatorSource=76,collectiveWeight=60,aileronWeight=60,elevatorWeight=60}) + elseif TypeFields[2][5]==2 then + model.setSwashRing({type="3",collectiveSource=77,aileronSource=78,elevatorSource=76,collectiveWeight=40,aileronWeight=40,elevatorWeight=60}) + elseif TypeFields[2][5]==3 then + model.setSwashRing({type="4",collectiveSource=77,aileronSource=78,elevatorSource=76,collectiveWeight=35,aileronWeight=35,elevatorWeight=60}) + end +end + +-- Init +local function init() + current, edit = 1, false + pages = { + runTypeConfig, + runStyleConfig, + runSwitchConfig, + runThrConfig, + runCurveConfig, + runAilerConfig, + runEleConfig, + runRudConfig, + runSummary, + runConfigSummary, + } +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE and page < #pages then + selectPage(1) + elseif event == EVT_VIRTUAL_ENTER_LONG and page == #pages then + runCreateModel(event) + lcd.drawText(0,15,"Model Sucessfully created !") + return 2 + elseif event == EVT_VIRTUAL_PREV_PAGE and page > 1 then + killEvents(event); + selectPage(-1) + end + local result = pages[page](event) + return result +end + +return { init=init, run=run } diff --git a/SCRIPTS/WIZARD/multi.lua b/SCRIPTS/WIZARD/multi.lua new file mode 100755 index 0000000..8878447 --- /dev/null +++ b/SCRIPTS/WIZARD/multi.lua @@ -0,0 +1,440 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### +-- Multicopter Wizard pages +local THROTTLE_PAGE = 0 +local ROLL_PAGE = 1 +local PITCH_PAGE = 2 +local YAW_PAGE = 3 +local ARM_PAGE = 4 +local MODE_PAGE = 5 +local BEEPER_PAGE = 6 +local CONFIRMATION_PAGE = 7 + +-- Navigation variables +local page = THROTTLE_PAGE +local dirty = true +local edit = false +local field = 0 +local fieldsMax = 0 +local comboBoxMode = 0 -- Scrap variable +local validSwitch = {} + +-- Model settings +local thrCH1 = 0 +local rollCH1 = 0 +local yawCH1 = 0 +local pitchCH1 = 0 +local armSW1 = 1 +local beeperSW1 = 1 +local modeSW1 = 1 +local switches = {} + +-- Common functions +local lastBlink = 0 +local function blinkChanged() + local time = getTime() % 128 + local blink = (time - time % 64) / 64 + if blink ~= lastBlink then + lastBlink = blink + return true + else + return false + end +end + +local function fieldIncDec(event, value, max, force) + if edit or force==true then + if event == EVT_VIRTUAL_INC then + value = (value + max) + dirty = true + elseif event == EVT_VIRTUAL_DEC then + value = (value + max + 2) + dirty = true + end + value = (value % (max+1)) + end + return value +end + +local function valueIncDec(event, value, min, max) + if edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + if value < max then + value = (value + 1) + dirty = true + end + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + if value > min then + value = (value - 1) + dirty = true + end + end + end + return value +end + +local function navigate(event, fieldMax, prevPage, nextPage) + if event == EVT_VIRTUAL_ENTER then + edit = not edit + dirty = true + elseif edit then + if event == EVT_VIRTUAL_EXIT then + edit = false + dirty = true + elseif not dirty then + dirty = blinkChanged() + end + else + if event == EVT_VIRTUAL_NEXT_PAGE then + page = nextPage + field = 0 + dirty = true + elseif event == EVT_VIRTUAL_PREV_PAGE then + page = prevPage + field = 0 + killEvents(event); + dirty = true + else + field = fieldIncDec(event, field, fieldMax, true) + end + end +end + +local function getFieldFlags(position) + flags = 0 + if field == position then + flags = INVERS + if edit then + flags = INVERS + BLINK + end + end + return flags +end + +local function channelIncDec(event, value) + if not edit and event==EVT_VIRTUAL_MENU then + servoPage = value + dirty = true + else + value = valueIncDec(event, value, 0, 15) + end + return value +end + +local function switchValueIncDec(event, value, min, max) + if edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + if value < max then + value = (value + 1) + dirty = true + end + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + if value > min then + value = (value - 1) + dirty = true + end + end + end + return value +end + +local function switchIncDec(event, value) + if not edit and event== EVT_VIRTUAL_MENU then + servoPage = value + dirty = true + else + value = switchValueIncDec(event, value, 1, #switches) + end + return value +end + +-- Init function +local function init() + thrCH1 = defaultChannel(2) + rollCH1 = defaultChannel(3) + yawCH1 = defaultChannel(0) + pitchCH1 = defaultChannel(1) + local ver, radio, maj, minor, rev = getVersion() + if string.match(radio, "x7") then + switches = {"SA", "SB", "SC", "SD", "SF", "SH"} + elseif string.match(radio, "tx12") then + switches = {"SA", "SB", "SC", "SD", "SE", "SF"} + else + switches = {"SA", "SB", "SC", "SD"} + end +end + +-- Throttle Menu +local function drawThrottleMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Throttle"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+thrCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function throttleMenu(event) + if dirty then + dirty = false + drawThrottleMenu() + end + navigate(event, fieldsMax, page, page+1) + thrCH1 = channelIncDec(event, thrCH1) +end + +-- Roll Menu +local function drawRollMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Roll"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+rollCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function rollMenu(event) + if dirty then + dirty = false + drawRollMenu() + end + navigate(event, fieldsMax, page-1, page+1) + rollCH1 = channelIncDec(event, rollCH1) +end + +-- Pitch Menu +local function drawPitchMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Pitch"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+pitchCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function pitchMenu(event) + if dirty then + dirty = false + drawPitchMenu() + end + navigate(event, fieldsMax, page-1, page+1) + pitchCH1 = channelIncDec(event, pitchCH1) +end + +-- Yaw Menu +local function drawYawMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Yaw"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+yawCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function yawMenu(event) + if dirty then + dirty = false + drawYawMenu() + end + navigate(event, fieldsMax, page-1, page+1) + yawCH1 = channelIncDec(event, yawCH1) +end + +-- Arm Menu +local function drawArmMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Arm"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign AUX1", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawText(25, 40, switches[armSW1], getFieldFlags(0)) + fieldsMax = 0 +end + +local function armMenu(event) + if dirty then + dirty = false + drawArmMenu() + end + navigate(event, fieldsMax, page-1, page+1) + armSW1 = switchIncDec(event, armSW1) +end + +-- Beeper Menu +local function drawbeeperMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Beeper"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign AUX2", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawText(25, 40, switches[beeperSW1], getFieldFlags(0)) + fieldsMax = 0 +end + +local function beeperMenu(event) + if dirty then + dirty = false + drawbeeperMenu() + end + navigate(event, fieldsMax, page-1, page+1) + beeperSW1 = switchIncDec(event, beeperSW1) +end + +-- Mode Menu +local function drawmodeMenu() + lcd.clear() + lcd.drawText(1, 0, "Multicopter", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, {"Mode"}, comboBoxMode, getFieldFlags(1)) + lcd.drawText(5, 30, "Assign AUX3", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawText(25, 40, switches[modeSW1], getFieldFlags(0)) + fieldsMax = 0 +end + +local function modeMenu(event) + if dirty then + dirty = false + drawmodeMenu() + end + navigate(event, fieldsMax, page-1, page+1) + modeSW1 = switchIncDec(event, modeSW1) +end + +-- Confirmation Menu +local function drawNextLine(x, y, label, channel) + lcd.drawText(x, y, label, 0); + lcd.drawText(x+46, y, ":", 0); + lcd.drawSource(x+50, y, MIXSRC_CH1+channel, 0) + y = y + 8 + if y > 50 then + y = 12 + x = 120 + end + return x, y +end + +local function drawNextSWLine(x, y, label, switch) + lcd.drawText(x, y, label, 0); + lcd.drawText(x+38, y, ":", 0); + lcd.drawText(x+42, y, switches[switch], 0) + y = y + 8 + if y > 50 then + y = 12 + x = 120 + end + return x, y +end + +local function drawConfirmationMenu() + local x = 1 + local y = 12 + lcd.clear() + lcd.drawText(0, 1, "Ready to go?", 0); + lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0) + x, y = drawNextLine(x, y, "Throttle", thrCH1) + x, y = drawNextLine(x, y, "Roll", rollCH1) + x, y = drawNextLine(x, y, "Pitch", pitchCH1) + x, y = drawNextLine(x, y, "Yaw", yawCH1) + local x = 72 + local y = 12 + x, y = drawNextSWLine(x, y, "Arm", armSW1) + x, y = drawNextSWLine(x, y, "Mode", modeSW1) + x, y = drawNextSWLine(x, y, "Beeper", beeperSW1) + lcd.drawText(0, LCD_H-8, "[Enter Long] to confirm", 0); + lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0) + fieldsMax = 0 +end + +local function addMix(channel, input, name, weight, index) + local mix = { source=input, name=name } + if weight ~= nil then + mix.weight = weight + end + if index == nil then + index = 0 + end + model.insertMix(channel, index, mix) +end + +local function applySettings() + model.defaultInputs() + model.deleteMixes() + addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Throttle") + addMix(rollCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Roll") + addMix(yawCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Yaw") + addMix(pitchCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch") + addMix(4, MIXSRC_SA + armSW1 - 1, "Arm") + addMix(5, MIXSRC_SA + beeperSW1 - 1, "Beeper") + addMix(6, MIXSRC_SA + modeSW1 - 1, "Mode") +end + +local function confirmationMenu(event) + if dirty then + dirty = false + drawConfirmationMenu() + end + + navigate(event, fieldsMax, BEEPER_PAGE, page) + + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_ENTER_LONG then + killEvents(event) + applySettings() + return 2 + else + return 0 + end +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + end + if page == THROTTLE_PAGE then + throttleMenu(event) + elseif page == ROLL_PAGE then + rollMenu(event) + elseif page == YAW_PAGE then + yawMenu(event) + elseif page == PITCH_PAGE then + pitchMenu(event) + elseif page == ARM_PAGE then + armMenu(event) + elseif page == BEEPER_PAGE then + beeperMenu(event) + elseif page == MODE_PAGE then + modeMenu(event) + elseif page == CONFIRMATION_PAGE then + return confirmationMenu(event) + end + return 0 +end + +return { init=init, run=run } diff --git a/SCRIPTS/WIZARD/plane.lua b/SCRIPTS/WIZARD/plane.lua new file mode 100755 index 0000000..0937bc0 --- /dev/null +++ b/SCRIPTS/WIZARD/plane.lua @@ -0,0 +1,582 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +---- # 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. # +---- # # +---- ######################################################################### +-- Plane Wizard pages +local ENGINE_PAGE = 0 +local AILERONS_PAGE = 1 +local FLAPERONS_PAGE = 2 +local BRAKES_PAGE = 3 +local TAIL_PAGE = 4 +local CONFIRMATION_PAGE = 5 + +-- Navigation variables +local page = ENGINE_PAGE +local dirty = true +local edit = false +local field = 0 +local fieldsMax = 0 + +-- Model settings +local engineMode = 1 +local thrCH1 = 0 +local aileronsMode = 1 +local ailCH1 = 0 +local ailCH2 = 5 +local flapsMode = 0 +local flapsCH1 = 6 +local flapsCH2 = 7 +local brakesMode = 0 +local brakesCH1 = 8 +local brakesCH2 = 9 +local tailMode = 1 +local eleCH1 = 0 +local eleCH2 = 4 +local rudCH1 = 0 +local servoPage = nil + +-- Common functions +local lastBlink = 0 +local function blinkChanged() + local time = getTime() % 128 + local blink = (time - time % 64) / 64 + if blink ~= lastBlink then + lastBlink = blink + return true + else + return false + end +end + +local function fieldIncDec(event, value, max, force) + if edit or force==true then + if event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + value = (value + max) + dirty = true + elseif event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + value = (value + max + 2) + dirty = true + end + value = (value % (max+1)) + end + return value +end + +local function valueIncDec(event, value, min, max) + if edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + if value < max then + value = (value + 1) + dirty = true + end + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + if value > min then + value = (value - 1) + dirty = true + end + end + end + return value +end + +local function navigate(event, fieldMax, prevPage, nextPage) + if event == EVT_VIRTUAL_ENTER then + edit = not edit + dirty = true + elseif edit then + if event == EVT_VIRTUAL_EXIT then + edit = false + dirty = true + elseif not dirty then + dirty = blinkChanged() + end + else + if event == EVT_VIRTUAL_NEXT_PAGE then + page = nextPage + field = 0 + dirty = true + elseif event == EVT_VIRTUAL_PREV_PAGE then + page = prevPage + field = 0 + killEvents(event); + dirty = true + else + field = fieldIncDec(event, field, fieldMax, true) + end + end +end + +local function getFieldFlags(position) + flags = 0 + if field == position then + flags = INVERS + if edit then + flags = INVERS + BLINK + end + end + return flags +end + +local function channelIncDec(event, value) + if not edit and event==EVT_VIRTUAL_MENU then + servoPage = value + dirty = true + else + value = valueIncDec(event, value, 0, 15) + end + return value +end + +-- Init function +local function init() + rudCH1 = defaultChannel(0) + eleCH1 = defaultChannel(1) + thrCH1 = defaultChannel(2) + ailCH1 = defaultChannel(3) +end + +-- Engine Menu +local engineModeItems = {"No", "Yes"} +local function drawEngineMenu() + lcd.clear() + if engineMode == 1 then + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+thrCH1, getFieldFlags(1)) + fieldsMax = 1 + else + -- No engine + fieldsMax = 0 + end + lcd.drawText(1, 0, "Got an engine?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, engineModeItems, engineMode, getFieldFlags(0)) +end + +local function engineMenu(event) + if dirty then + dirty = false + drawEngineMenu() + end + + navigate(event, fieldsMax, page, page+1) + + if field==0 then + engineMode = fieldIncDec(event, engineMode, 1) + elseif field==1 then + thrCH1 = channelIncDec(event, thrCH1) + end +end + +-- Ailerons Menu +local aileronsModeItems = {"No", "Yes, 1 channel", "Yes, 2 channels"} +local function drawAileronsMenu() + lcd.clear() + if aileronsMode == 2 then + -- 2 channels + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(30, 40, "L", 0); + lcd.drawText(65, 40, "R", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+ailCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+ailCH2, getFieldFlags(2)) + fieldsMax = 2 + elseif aileronsMode == 1 then + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+ailCH1, getFieldFlags(1)) + fieldsMax = 1 + else + -- No ailerons + fieldsMax = 0 + end + lcd.drawText(1, 0, "Got ailerons?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, aileronsModeItems, aileronsMode, getFieldFlags(0)) +end + +local function aileronsMenu(event) + if dirty then + dirty = false + drawAileronsMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + aileronsMode = fieldIncDec(event, aileronsMode, 2) + elseif field==1 then + ailCH1 = channelIncDec(event, ailCH1) + elseif field==2 then + ailCH2 = channelIncDec(event, ailCH2) + end +end + +-- Flaps Menu +local flapsModeItems = {"No", "Yes, 1 channel", "Yes, 2 channels"} +local function drawFlapsMenu() + lcd.clear() + if flapsMode == 0 then + -- no flaps + fieldsMax = 0 + elseif flapsMode == 1 then + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+flapsCH1, getFieldFlags(1)) + fieldsMax = 1 + elseif flapsMode == 2 then + -- 2 channels + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(30, 40, "L", 0); + lcd.drawText(65, 40, "R", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+flapsCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+flapsCH2, getFieldFlags(2)) + fieldsMax = 2 + end + lcd.drawText(1, 0, "Got flaps?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, flapsModeItems, flapsMode, getFieldFlags(0)) +end + +local function flapsMenu(event) + if dirty then + dirty = false + drawFlapsMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + flapsMode = fieldIncDec(event, flapsMode, 2) + elseif field==1 then + flapsCH1 = channelIncDec(event, flapsCH1) + elseif field==2 then + flapsCH2 = channelIncDec(event, flapsCH2) + end +end + +-- Airbrakes Menu +local brakesModeItems = {"No", "Yes, 1 channel", "Yes, 2 channels"} +local function drawBrakesMenu() + lcd.clear() + if brakesMode == 0 then + -- no brakes + fieldsMax = 0 + elseif brakesMode == 1 then + -- 1 channel + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+brakesCH1, getFieldFlags(1)) + fieldsMax = 1 + elseif brakesMode == 2 then + -- 2 channels + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(30, 40, "L", 0); + lcd.drawText(65, 40, "R", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+brakesCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+brakesCH2, getFieldFlags(2)) + fieldsMax = 2 + end + lcd.drawText(1, 0, "Got air brakes?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, brakesModeItems, brakesMode, getFieldFlags(0)) +end + +local function brakesMenu(event) + if dirty then + dirty = false + drawBrakesMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + brakesMode = fieldIncDec(event, brakesMode, 2) + elseif field==1 then + brakesCH1 = channelIncDec(event, brakesCH1) + elseif field==2 then + brakesCH2 = channelIncDec(event, brakesCH2) + end +end + +-- Tail Menu +local tailModeItems = {"Ele(1)", "Ele(1) + Ruder(1)", "Ele(2) + Ruder(1)", "V-Tail(2)"} +local function drawTailMenu() + lcd.clear() + if tailMode == 0 then + -- Elevator(1ch), no rudder... + lcd.drawText(5, 30, "Assign channel", 0); + lcd.drawText(5, 40, ">>>", 0); + lcd.drawSource(25, 40, MIXSRC_CH1+eleCH1, getFieldFlags(1)) + fieldsMax = 1 + elseif tailMode == 1 then + -- Elevator(1ch) + rudder... + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(25, 40, "Ele", 0); + lcd.drawText(60, 40, "Rud", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+eleCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+rudCH1, getFieldFlags(2)) + fieldsMax = 2 + elseif tailMode == 2 then + -- Elevator(2ch) + rudder... + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(25, 40, "EleL", 0); + lcd.drawText(60, 40, "EleR", 0); + lcd.drawText(95, 40, "Rud", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+eleCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+eleCH2, getFieldFlags(2)) + lcd.drawSource(95, 50, MIXSRC_CH1+rudCH1, getFieldFlags(3)) + fieldsMax = 3 + else + -- V-Tail... + lcd.drawText(5, 30, "Assign channels", 0); + lcd.drawText(25, 40, "VtaL", 0); + lcd.drawText(60, 40, "VtaR", 0); + lcd.drawText(5, 50, ">>>", 0); + lcd.drawSource(25, 50, MIXSRC_CH1+eleCH1, getFieldFlags(1)) + lcd.drawSource(60, 50, MIXSRC_CH1+eleCH2, getFieldFlags(2)) + fieldsMax = 2 + end + lcd.drawText(1, 0, "Tail config", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W, tailModeItems, tailMode, getFieldFlags(0)) +end + +local function tailMenu(event) + if dirty then + dirty = false + drawTailMenu() + end + + navigate(event, fieldsMax, page-1, page+1) + + if field==0 then + tailMode = fieldIncDec(event, tailMode, 3) + elseif field==1 then + eleCH1 = channelIncDec(event, eleCH1) + elseif (field==2 and tailMode==1) or field==3 then + rudCH1 = channelIncDec(event, rudCH1) + elseif field==2 then + eleCH2 = channelIncDec(event, eleCH2) + end +end + +-- Servo (limits) Menu +local function drawServoMenu(limits) + lcd.clear() + lcd.drawSource(1, 0, MIXSRC_CH1+servoPage, 0) + lcd.drawText(25, 0, "servo min/max/center/direction?", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, FILL_WHITE) + lcd.drawLine(LCD_W/2-1, 8, LCD_W/2-1, LCD_H, DOTTED, 0) + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawNumber(140, 35, limits.min, PREC1+getFieldFlags(0)); + lcd.drawNumber(205, 35, limits.max, PREC1+getFieldFlags(1)); + lcd.drawNumber(170, 9, limits.offset, PREC1+getFieldFlags(2)); + if limits.revert == 0 then + lcd.drawText(129, 50, "\126", getFieldFlags(3)); + else + lcd.drawText(129, 50, "\127", getFieldFlags(3)); + end + fieldsMax = 3 +end + +local function servoMenu(event) + local limits = model.getOutput(servoPage) + + if dirty then + dirty = false + drawServoMenu(limits) + end + + navigate(event, fieldsMax, page, page) + + if edit then + if field==0 then + limits.min = valueIncDec(event, limits.min, -1000, 0) + elseif field==1 then + limits.max = valueIncDec(event, limits.max, 0, 1000) + elseif field==2 then + limits.offset = valueIncDec(event, limits.offset, -1000, 1000) + elseif field==3 then + limits.revert = fieldIncDec(event, limits.revert, 1) + end + model.setOutput(servoPage, limits) + elseif event == EVT_VIRTUAL_EXIT then + servoPage = nil + dirty = true + end +end + +-- Confirmation Menu +local function drawNextLine(x, y, label, channel) + lcd.drawText(x, y, label, 0); + lcd.drawText(x+26, y, ":", 0); + lcd.drawSource(x+30, y, MIXSRC_CH1+channel, 0) + y = y + 8 + if y > 50 then + y = 12 + x = 70 + end + return x, y +end + +local function drawConfirmationMenu() + local x = 5 + local y = 12 + lcd.clear() + lcd.drawText(0, 1, "Ready to go?", 0); + lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0) + if engineMode == 1 then + x, y = drawNextLine(x, y, "Thr", thrCH1) + end + if aileronsMode == 1 then + x, y = drawNextLine(x, y, "Ail", ailCH1) + elseif aileronsMode == 2 then + x, y = drawNextLine(x, y, "AilL", ailCH1) + x, y = drawNextLine(x, y, "AilR", ailCH2) + end + if flapsMode == 1 then + x, y = drawNextLine(x, y, "Flap", flapsCH1) + elseif flapsMode == 2 then + x, y = drawNextLine(x, y, "FlpL", flapsCH1) + x, y = drawNextLine(x, y, "FlpR", flapsCH2) + end + if brakesMode == 1 then + x, y = drawNextLine(x, y, "Brak", brakesCH1) + elseif brakesMode == 2 then + x, y = drawNextLine(x, y, "BrkL", brakesCH1) + x, y = drawNextLine(x, y, "BrkR", brakesCH2) + end + if tailMode == 3 then + x, y = drawNextLine(x, y, "VtaL", eleCH1) + x, y = drawNextLine(x, y, "VtaR", eleCH2) + else + x, y = drawNextLine(x, y, "Rud", rudCH1) + if tailMode == 1 then + x, y = drawNextLine(x, y, "Elev", eleCH1) + elseif tailMode == 2 then + x, y = drawNextLine(x, y, "EleL", eleCH1) + x, y = drawNextLine(x, y, "EleR", eleCH2) + end + end + lcd.drawText(0, LCD_H-8, "[Enter Long] to confirm", 0); + lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0) + fieldsMax = 0 +end + +local function addMix(channel, input, name, weight, index) + local mix = { source=input, name=name } + if weight ~= nil then + mix.weight = weight + end + if index == nil then + index = 0 + end + model.insertMix(channel, index, mix) +end + +local function applySettings() + model.defaultInputs() + model.deleteMixes() + if engineMode > 0 then + addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Engine") + end + if aileronsMode == 1 then + addMix(ailCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Ail") + elseif aileronsMode == 2 then + addMix(ailCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "AilL", -100) + addMix(ailCH2, MIXSRC_FIRST_INPUT+defaultChannel(3), "AilR") + end + if flapsMode == 1 then + addMix(flapsCH1, MIXSRC_SA, "Flap") + elseif flapsMode == 2 then + addMix(flapsCH1, MIXSRC_SA, "FlapL") + addMix(flapsCH2, MIXSRC_SA, "FlapR") + end + if brakesMode == 1 then + addMix(brakesCH1, MIXSRC_SD, "Brake") + elseif brakesMode == 2 then + addMix(brakesCH1, MIXSRC_SD, "BrakeL") + addMix(brakesCH2, MIXSRC_SD, "BrakeR") + end + if tailMode == 3 then + addMix(eleCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "V-EleL", 50) + addMix(eleCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "V-RudL", -50, 1) + addMix(eleCH2, MIXSRC_FIRST_INPUT+defaultChannel(1), "V-EleR", 50) + addMix(eleCH2, MIXSRC_FIRST_INPUT+defaultChannel(0), "V-RudR", 50, 1) + else + if tailMode > 0 then + addMix(rudCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Rudder") + end + if tailMode == 1 then + addMix(eleCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Elev") + elseif tailMode == 2 then + addMix(eleCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "ElevG") + addMix(eleCH2, MIXSRC_FIRST_INPUT+defaultChannel(1), "ElevD") + end + end +end + +local function confirmationMenu(event) + if dirty then + dirty = false + drawConfirmationMenu() + end + + navigate(event, fieldsMax, TAIL_PAGE, page) + + if event == EVT_VIRTUAL_EXIT then + return 2 + elseif event == EVT_VIRTUAL_ENTER_LONG then + killEvents(event) + applySettings() + return 2 + else + return 0 + end +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + end + + if servoPage ~= nil then + servoMenu(event) + elseif page == ENGINE_PAGE then + engineMenu(event) + elseif page == AILERONS_PAGE then + aileronsMenu(event) + elseif page == FLAPERONS_PAGE then + flapsMenu(event) + elseif page == BRAKES_PAGE then + brakesMenu(event) + elseif page == TAIL_PAGE then + tailMenu(event) + elseif page == CONFIRMATION_PAGE then + return confirmationMenu(event) + end + return 0 +end + +return { init=init, run=run } diff --git a/SCRIPTS/WIZARD/wizard.lua b/SCRIPTS/WIZARD/wizard.lua new file mode 100755 index 0000000..61b8160 --- /dev/null +++ b/SCRIPTS/WIZARD/wizard.lua @@ -0,0 +1,87 @@ +---- ######################################################################### +---- # # +---- # 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. # +---- # # +---- ######################################################################### + +-- Model types +local modelType = 0 +local MODELTYPE_PLANE = 0 +local MODELTYPE_DELTA = 1 +local MODELTYPE_QUAD = 2 +local MODELTYPE_HELI = 3 +-- Common functions +local function fieldIncDec(event, value, max) + if event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + value = (value - 1) + elseif event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + value = (value + max + 3) + end + value = (value % (max+2)) + return value +end + +-- Model Type Menu +local function modelTypeSurround(index) + if index <= 1 then + lcd.drawFilledRectangle(59*(index%2)+12, 13, 43, 23) + else + lcd.drawFilledRectangle(59*(index%2)+12, 34, 40, 20) + end +end + +local function drawModelChoiceMenu() + lcd.clear() + lcd.drawScreenTitle("Select model type", 0, 0) + lcd.drawText( 20, 20, "Plane") + lcd.drawText( 78, 20, "Delta") + lcd.drawText( 20, 40, "Multi") + lcd.drawText( 78, 40, "Heli") + modelTypeSurround(modelType) + fieldsMax = 0 +end + +local function modelTypeMenu(event) + drawModelChoiceMenu() + if event == EVT_VIRTUAL_ENTER then + if modelType == MODELTYPE_PLANE then + return "plane.lua" + elseif modelType == MODELTYPE_DELTA then + return "delta.lua" + elseif modelType == MODELTYPE_QUAD then + return "multi.lua" + elseif modelType == MODELTYPE_HELI then + return "heli.lua" + end + else + modelType = fieldIncDec(event, modelType, 2) + end + return 0 +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + end + + if event == EVT_VIRTUAL_EXIT then + return 2 + end + + + return modelTypeMenu(event) +end + +return { run=run } diff --git a/SCRIPTS/WIZARD/wizard.luac b/SCRIPTS/WIZARD/wizard.luac new file mode 100755 index 0000000..aa5a19f Binary files /dev/null and b/SCRIPTS/WIZARD/wizard.luac differ diff --git a/SCRIPTS/simulator.txt b/SCRIPTS/simulator.txt new file mode 100755 index 0000000..d871238 --- /dev/null +++ b/SCRIPTS/simulator.txt @@ -0,0 +1 @@ + 3 \ No newline at end of file diff --git a/SCRIPTS/snake.lua b/SCRIPTS/snake.lua new file mode 100755 index 0000000..b937f04 --- /dev/null +++ b/SCRIPTS/snake.lua @@ -0,0 +1,176 @@ +-------------------------------------------------------------- +-- Classic snake game +-- +-- 2009 Led Lab @PUC-Rio www.eluaproject.net +-- Dado Sutter +-- Ives Negreiros +-- To Benjamin +--------------------------------------------------------------- + +local xMax = math.floor( LCD_W / 6 ) - 1 +local yMax = math.floor( LCD_H / 8 ) - 1 +local game_map = {} + +local Head = {} +local Tail = {} + +local highscore = 0 +local size = 3 +Tail.x = 1 +Tail.y = 1 +Head.x = Tail.x + ( size - 1 ) +Head.y = Tail.y + +local Food = {} +Food.x = false +Food.y = false + +Head.dx = 1 +Head.dy = 0 +Tail.dx = Head.dx +Tail.dy = Head.dy +local direction = "right" +local score = 0 + +local function create_food() + Food.x, Food.y = math.random( xMax - 1), math.random( yMax - 1) + while game_map[ Food.x ][ Food.y ] do + Food.x, Food.y = math.random( xMax - 1 ), math.random( yMax - 1 ) + end + game_map[ Food.x ][ Food.y ] = "food" + lcd.drawText( Food.x * 6, Food.y * 8+2, "@", 0 ) +end + +local function eat_food() + playFile("/SCRIPTS/snake.wav") + lcd.drawText( Head.x * 6, Head.y * 8, " ", 0 ) + game_map[ Head.x ][ Head.y ] = nil + create_food() + score = score + 1 +end + +local function check_collision() + if Head.x < 0 or Head.x > xMax then + return true + elseif Head.y < 0 or Head.y > yMax then + return true + elseif ( ( game_map[ Head.x ][ Head.y ] ) and ( game_map[ Head.x ][ Head.y ] ~= "food" ) ) then + return true + end + return false +end + +local function move() + if game_map[ Tail.x ][ Tail.y ] == "right" then + Tail.dx = 1 + Tail.dy = 0 + elseif game_map[ Tail.x ][ Tail.y ] == "left" then + Tail.dx = -1 + Tail.dy = 0 + elseif game_map[ Tail.x ][ Tail.y ] == "up" then + Tail.dx = 0 + Tail.dy = -1 + elseif game_map[ Tail.x ][ Tail.y ] == "down" then + Tail.dx = 0 + Tail.dy = 1 + end + + game_map[ Head.x ][ Head.y ] = direction + Head.x = Head.x + Head.dx + Head.y = Head.y + Head.dy + + if Head.x < 0 or Head.x > xMax or Head.y < 0 or Head.y > yMax then + return + elseif game_map[ Head.x ][ Head.y ] == "food" then + eat_food() + else + lcd.drawText(Tail.x * 6, Tail.y * 8, " ", 16) + game_map[ Tail.x ][ Tail.y ] = nil + Tail.x = Tail.x + Tail.dx + Tail.y = Tail.y + Tail.dy + end + + lcd.drawText(Head.x * 6, Head.y * 8, "*", 0) +end + +local function init() + food = false + lcd.clear() + size = 3 + score = 0 + Tail.x = 1 + Tail.y = 1 + Head.x = Tail.x + ( size - 1 ) + Head.y = Tail.y + Head.dx = 1 + Head.dy = 0 + Tail.dx = Head.dx + Tail.dy = Head.dy + direction = "right" + + for i = 0, xMax, 1 do + game_map[ i ] = {} + end + + for i = 0, size - 1, 1 do + game_map[ Tail.x + ( i * Tail.dx ) ][ Tail.y + ( i * Tail.dy ) ] = direction + lcd.drawText( ( Tail.x + ( i * Tail.dx ) ) * 6, ( Tail.y + ( i * Tail.dy ) ) * 8, "*", 0 ) + end + + create_food() +end + +local snakeCounter = 0 + +local function run(event) + if event == nil then + raise("Cannot be run as a model script!") + end + + if event == EVT_VIRTUAL_EXIT then + return 2 + end + + snakeCounter = snakeCounter + 1 + if snakeCounter < 30 then + return 0 + end + + snakeCounter = 0 + + local dir = direction + if getValue('rud') > 100 and direction ~= "left" then + dir = "right" + Head.dx = 1 + Head.dy = 0 + end + if getValue('rud') < -100 and direction ~= "right" then + dir = "left" + Head.dx = -1 + Head.dy = 0 + end + if getValue('ele') > 100 and direction ~= "down" then + dir = "up" + Head.dx = 0 + Head.dy = -1 + end + if getValue('ele') < -100 and direction ~= "up" then + dir = "down" + Head.dx = 0 + Head.dy = 1 + end + + direction = dir + move() + + lcd.refresh() + + if check_collision() then + return 1 + end + + return 0 +end + +return { init=init, run=run } + diff --git a/SOUNDS/README.txt b/SOUNDS/README.txt new file mode 100755 index 0000000..bd0837b --- /dev/null +++ b/SOUNDS/README.txt @@ -0,0 +1,2 @@ +Sound packs organised by language are stored in this directory. e.g. en, de, fr +You can also add your own model dependent sounds. diff --git a/SOUNDS/edgetx.sounds.version b/SOUNDS/edgetx.sounds.version new file mode 100755 index 0000000..805579f --- /dev/null +++ b/SOUNDS/edgetx.sounds.version @@ -0,0 +1 @@ +v2.11.0 \ No newline at end of file diff --git a/edgetx.sdcard.target b/edgetx.sdcard.target new file mode 100755 index 0000000..48053ec --- /dev/null +++ b/edgetx.sdcard.target @@ -0,0 +1 @@ +mt12 \ No newline at end of file diff --git a/edgetx.sdcard.version b/edgetx.sdcard.version new file mode 100755 index 0000000..805579f --- /dev/null +++ b/edgetx.sdcard.version @@ -0,0 +1 @@ +v2.11.0 \ No newline at end of file