Initial Commit

This commit is contained in:
Annika Merris 2025-06-26 07:54:22 -04:00
commit 933eee69e4
216 changed files with 20588 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/FIRMWARE/*.bin
*.wav
.DS_Store

682
BACKUP/CAR2-2023-10-06.yml Executable file
View file

@ -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

2
FIRMWARE/readme.txt Executable file
View file

@ -0,0 +1,2 @@
You can put firmware for your modules or radio in this folder.
Files in this folder are NOT automatically applied.

1
LOGS/readme.txt Executable file
View file

@ -0,0 +1 @@
Logs files created by "SD Logs" special function will be stored in this directory.

3
MODELS/README.txt Executable file
View file

@ -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.

525
MODELS/model00.yml Normal file
View file

@ -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

395
MODELS/model01.yml Normal file
View file

@ -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

550
MODELS/model02.yml Normal file
View file

@ -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

251
MODELS/model03.yml Normal file
View file

@ -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

232
MODELS/model04.yml Normal file
View file

@ -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

383
MODELS/model05.yml Normal file
View file

@ -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

383
MODELS/model06.yml Executable file
View file

@ -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

1
RADIO/README.txt Executable file
View file

@ -0,0 +1 @@
Radio specific configuration files are stored in this directory.

183
RADIO/radio.yml Executable file
View file

@ -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

1
SCREENSHOTS/readme.txt Executable file
View file

@ -0,0 +1 @@
Screenshots created by "Screenshot" special function will be stored in this directory.

1
SCRIPTS/FUNCTIONS/readme.txt Executable file
View file

@ -0,0 +1 @@
This directory is for Lua functions scripts.

1
SCRIPTS/MIXES/readme.txt Executable file
View file

@ -0,0 +1 @@
This directory is for Lua mixer scripts.

68
SCRIPTS/RGBLED/Bback.lua Executable file
View file

@ -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 }

68
SCRIPTS/RGBLED/Bfwrd.lua Executable file
View file

@ -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 }

68
SCRIPTS/RGBLED/Pback.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/Pback.luac Executable file

Binary file not shown.

68
SCRIPTS/RGBLED/Pfwrd.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/Pfwrd.luac Executable file

Binary file not shown.

1
SCRIPTS/RGBLED/README.md Executable file
View file

@ -0,0 +1 @@
This folder contains sample RGB Lua scripts, for radios which support this capability.

16
SCRIPTS/RGBLED/blue.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/blue.luac Executable file

Binary file not shown.

52
SCRIPTS/RGBLED/flow.lua Executable file
View file

@ -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 }

16
SCRIPTS/RGBLED/green.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/green.luac Executable file

Binary file not shown.

16
SCRIPTS/RGBLED/off.lua Executable file
View file

@ -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 }

16
SCRIPTS/RGBLED/orange.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/orange.luac Normal file

Binary file not shown.

26
SCRIPTS/RGBLED/police.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/police.luac Executable file

Binary file not shown.

16
SCRIPTS/RGBLED/purple.lua Executable file
View file

@ -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 }

52
SCRIPTS/RGBLED/rainbw.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/rainbw.luac Executable file

Binary file not shown.

16
SCRIPTS/RGBLED/red.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/red.luac Executable file

Binary file not shown.

53
SCRIPTS/RGBLED/rgbLop.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/rgbLop.luac Normal file

Binary file not shown.

77
SCRIPTS/RGBLED/runner.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/runner.luac Executable file

Binary file not shown.

16
SCRIPTS/RGBLED/sapp.lua Executable file
View file

@ -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 }

16
SCRIPTS/RGBLED/white.lua Executable file
View file

@ -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 }

16
SCRIPTS/RGBLED/yellow.lua Executable file
View file

@ -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 }

BIN
SCRIPTS/RGBLED/yellow.luac Normal file

Binary file not shown.

63
SCRIPTS/TELEMETRY/gplusl.lua Executable file
View file

@ -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}

2
SCRIPTS/TELEMETRY/readme.txt Executable file
View file

@ -0,0 +1,2 @@
This directory is for Lua telemetry scripts.
Those scripts can be selected using DISPLAY screen in MODEL SETUP.

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

File diff suppressed because it is too large Load diff

View file

@ -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 }

File diff suppressed because it is too large Load diff

View file

@ -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 }

View file

@ -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 }

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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 }

View file

@ -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

View file

@ -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

View file

@ -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 }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
-- OVERRIDES Messges for MIN 128x64 screns
-- FORMAT <LineType>|<Msg#>|<Text>
-- 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show more