1 ---- #########################################################################
3 ---- # Copyright (C) OpenTX #
5 ---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
7 ---- # This program is free software; you can redistribute it and/or modify #
8 ---- # it under the terms of the GNU General Public License version 2 as #
9 ---- # published by the Free Software Foundation. #
11 ---- # This program is distributed in the hope that it will be useful #
12 ---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 ---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 ---- # GNU General Public License for more details. #
16 ---- #########################################################################
19 local AILERONS_PAGE
= 1
20 local FLAPERONS_PAGE
= 2
23 local CONFIRMATION_PAGE
= 5
25 -- Navigation variables
26 local page
= ENGINE_PAGE
35 local aileronsMode
= 1
52 local function blinkChanged()
53 local time
= getTime() % 128
54 local blink
= (time
- time
% 64) / 64
55 if blink
~= lastBlink
then
63 local function fieldIncDec(event
, value
, max, force
)
64 if edit
or force
==true then
65 if event
== EVT_ROT_LEFT
then
68 elseif event
== EVT_ROT_RIGHT
then
69 value
= (value
+ max + 2)
72 value
= (value
% (max+1))
77 local function valueIncDec(event
, value
, min, max)
79 if event
== EVT_ROT_LEFT
or event
== EVT_ROT_LEFT
then
84 elseif event
== EVT_ROT_RIGHT
or event
== EVT_ROT_RIGHT
then
94 local function navigate(event
, fieldMax
, prevPage
, nextPage
)
95 if event
== EVT_ENTER_BREAK
then
99 if event
== EVT_EXIT_BREAK
then
102 elseif not dirty
then
103 dirty
= blinkChanged()
106 if event
== EVT_PAGE_BREAK
then
110 elseif event
== EVT_PAGE_LONG
then
116 field
= fieldIncDec(event
, field
, fieldMax
, true)
121 local function getFieldFlags(position
)
123 if field
== position
then
126 flags
= INVERS
+ BLINK
132 local function channelIncDec(event
, value
)
133 if not edit
and event
==EVT_MENU_BREAK
then
137 value
= valueIncDec(event
, value
, 0, 15)
143 local function init()
144 rudCH1
= defaultChannel(0)
145 eleCH1
= defaultChannel(1)
146 thrCH1
= defaultChannel(2)
147 ailCH1
= defaultChannel(3)
151 local engineModeItems
= {"No", "Yes"}
152 local function drawEngineMenu()
154 if engineMode
== 1 then
156 lcd
.drawText(5, 30, "Assign channel", 0);
157 lcd
.drawText(5, 40, ">>>", 0);
158 lcd
.drawSource(25, 40, MIXSRC_CH1
+thrCH1
, getFieldFlags(1))
164 lcd
.drawText(1, 0, "Got an engine?", 0)
165 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
166 lcd
.drawCombobox(0, 8, LCD_W
, engineModeItems
, engineMode
, getFieldFlags(0))
169 local function engineMenu(event
)
175 navigate(event
, fieldsMax
, page
, page
+1)
178 engineMode
= fieldIncDec(event
, engineMode
, 1)
180 thrCH1
= channelIncDec(event
, thrCH1
)
185 local aileronsModeItems
= {"No", "Yes", "Yes, 2 channels"}
186 local function drawAileronsMenu()
188 if aileronsMode
== 2 then
190 lcd
.drawText(5, 30, "Assign channels", 0);
191 lcd
.drawText(30, 40, "L", 0);
192 lcd
.drawText(65, 40, "R", 0);
193 lcd
.drawText(5, 50, ">>>", 0);
194 lcd
.drawSource(25, 50, MIXSRC_CH1
+ailCH1
, getFieldFlags(1))
195 lcd
.drawSource(60, 50, MIXSRC_CH1
+ailCH2
, getFieldFlags(2))
197 elseif aileronsMode
== 1 then
199 lcd
.drawText(5, 30, "Assign channel", 0);
200 lcd
.drawText(5, 40, ">>>", 0);
201 lcd
.drawSource(25, 40, MIXSRC_CH1
+ailCH1
, getFieldFlags(1))
207 lcd
.drawText(1, 0, "Got ailerons?", 0)
208 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
209 lcd
.drawCombobox(0, 8, LCD_W
, aileronsModeItems
, aileronsMode
, getFieldFlags(0))
212 local function aileronsMenu(event
)
218 navigate(event
, fieldsMax
, page
-1, page
+1)
221 aileronsMode
= fieldIncDec(event
, aileronsMode
, 2)
223 ailCH1
= channelIncDec(event
, ailCH1
)
225 ailCH2
= channelIncDec(event
, ailCH2
)
230 local flapsModeItems
= {"No", "Yes", "Yes, 2 channels"}
231 local function drawFlapsMenu()
233 if flapsMode
== 0 then
236 elseif flapsMode
== 1 then
238 lcd
.drawText(5, 30, "Assign channel", 0);
239 lcd
.drawText(5, 40, ">>>", 0);
240 lcd
.drawSource(25, 40, MIXSRC_CH1
+flapsCH1
, getFieldFlags(1))
242 elseif flapsMode
== 2 then
244 lcd
.drawText(5, 30, "Assign channels", 0);
245 lcd
.drawText(30, 40, "L", 0);
246 lcd
.drawText(65, 40, "R", 0);
247 lcd
.drawText(5, 50, ">>>", 0);
248 lcd
.drawSource(25, 50, MIXSRC_CH1
+flapsCH1
, getFieldFlags(1))
249 lcd
.drawSource(60, 50, MIXSRC_CH1
+flapsCH2
, getFieldFlags(2))
252 lcd
.drawText(1, 0, "Got flaps?", 0)
253 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
254 lcd
.drawCombobox(0, 8, LCD_W
, flapsModeItems
, flapsMode
, getFieldFlags(0))
257 local function flapsMenu(event
)
263 navigate(event
, fieldsMax
, page
-1, page
+1)
266 flapsMode
= fieldIncDec(event
, flapsMode
, 2)
268 flapsCH1
= channelIncDec(event
, flapsCH1
)
270 flapsCH2
= channelIncDec(event
, flapsCH2
)
275 local brakesModeItems
= {"No", "Yes", "Yes, 2 channels"}
276 local function drawBrakesMenu()
278 if brakesMode
== 0 then
281 elseif brakesMode
== 1 then
283 lcd
.drawText(5, 30, "Assign channel", 0);
284 lcd
.drawText(5, 40, ">>>", 0);
285 lcd
.drawSource(25, 40, MIXSRC_CH1
+brakesCH1
, getFieldFlags(1))
287 elseif brakesMode
== 2 then
289 lcd
.drawText(5, 30, "Assign channels", 0);
290 lcd
.drawText(30, 40, "L", 0);
291 lcd
.drawText(65, 40, "R", 0);
292 lcd
.drawText(5, 50, ">>>", 0);
293 lcd
.drawSource(25, 50, MIXSRC_CH1
+brakesCH1
, getFieldFlags(1))
294 lcd
.drawSource(60, 50, MIXSRC_CH1
+brakesCH2
, getFieldFlags(2))
297 lcd
.drawText(1, 0, "Got air brakes?", 0)
298 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
299 lcd
.drawCombobox(0, 8, LCD_W
, brakesModeItems
, brakesMode
, getFieldFlags(0))
302 local function brakesMenu(event
)
308 navigate(event
, fieldsMax
, page
-1, page
+1)
311 brakesMode
= fieldIncDec(event
, brakesMode
, 2)
313 brakesCH1
= channelIncDec(event
, brakesCH1
)
315 brakesCH2
= channelIncDec(event
, brakesCH2
)
320 local tailModeItems
= {"Ele(1)", "Ele(1) + Ruder(1)", "Ele(2) + Ruder(1)", "V-Tail(2)"}
321 local function drawTailMenu()
323 if tailMode
== 0 then
324 -- Elevator(1ch), no rudder...
325 lcd
.drawText(5, 30, "Assign channel", 0);
326 lcd
.drawText(5, 40, ">>>", 0);
327 lcd
.drawSource(25, 40, MIXSRC_CH1
+eleCH1
, getFieldFlags(1))
329 elseif tailMode
== 1 then
330 -- Elevator(1ch) + rudder...
331 lcd
.drawText(5, 30, "Assign channels", 0);
332 lcd
.drawText(25, 40, "Ele", 0);
333 lcd
.drawText(60, 40, "Rud", 0);
334 lcd
.drawText(5, 50, ">>>", 0);
335 lcd
.drawSource(25, 50, MIXSRC_CH1
+eleCH1
, getFieldFlags(1))
336 lcd
.drawSource(60, 50, MIXSRC_CH1
+rudCH1
, getFieldFlags(2))
338 elseif tailMode
== 2 then
339 -- Elevator(2ch) + rudder...
340 lcd
.drawText(5, 30, "Assign channels", 0);
341 lcd
.drawText(25, 40, "EleL", 0);
342 lcd
.drawText(60, 40, "EleR", 0);
343 lcd
.drawText(95, 40, "Rud", 0);
344 lcd
.drawText(5, 50, ">>>", 0);
345 lcd
.drawSource(25, 50, MIXSRC_CH1
+eleCH1
, getFieldFlags(1))
346 lcd
.drawSource(60, 50, MIXSRC_CH1
+eleCH2
, getFieldFlags(2))
347 lcd
.drawSource(95, 50, MIXSRC_CH1
+rudCH1
, getFieldFlags(3))
351 lcd
.drawText(5, 30, "Assign channels", 0);
352 lcd
.drawText(25, 40, "VtaL", 0);
353 lcd
.drawText(60, 40, "VtaR", 0);
354 lcd
.drawText(5, 50, ">>>", 0);
355 lcd
.drawSource(25, 50, MIXSRC_CH1
+eleCH1
, getFieldFlags(1))
356 lcd
.drawSource(60, 50, MIXSRC_CH1
+eleCH2
, getFieldFlags(2))
359 lcd
.drawText(1, 0, "Tail config", 0)
360 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
361 lcd
.drawCombobox(0, 8, LCD_W
, tailModeItems
, tailMode
, getFieldFlags(0))
364 local function tailMenu(event
)
370 navigate(event
, fieldsMax
, page
-1, page
+1)
373 tailMode
= fieldIncDec(event
, tailMode
, 3)
375 eleCH1
= channelIncDec(event
, eleCH1
)
376 elseif (field
==2 and tailMode
==1) or field
==3 then
377 rudCH1
= channelIncDec(event
, rudCH1
)
379 eleCH2
= channelIncDec(event
, eleCH2
)
383 -- Servo (limits) Menu
384 local function drawServoMenu(limits
)
386 lcd
.drawSource(1, 0, MIXSRC_CH1
+servoPage
, 0)
387 lcd
.drawText(25, 0, "servo min/max/center/direction?", 0)
388 lcd
.drawFilledRectangle(0, 0, LCD_W
, 8, FILL_WHITE
)
389 lcd
.drawLine(LCD_W
/2-1, 8, LCD_W
/2-1, LCD_H
, DOTTED
, 0)
390 lcd
.drawText(LCD_W
/2-19, LCD_H
-8, ">>>", 0);
391 lcd
.drawNumber(140, 35, limits
.min, PREC1
+getFieldFlags(0));
392 lcd
.drawNumber(205, 35, limits
.max, PREC1
+getFieldFlags(1));
393 lcd
.drawNumber(170, 9, limits
.offset
, PREC1
+getFieldFlags(2));
394 if limits
.revert
== 0 then
395 lcd
.drawText(129, 50, "\126", getFieldFlags(3));
397 lcd
.drawText(129, 50, "\127", getFieldFlags(3));
402 local function servoMenu(event
)
403 local limits
= model
.getOutput(servoPage
)
407 drawServoMenu(limits
)
410 navigate(event
, fieldsMax
, page
, page
)
414 limits
.min = valueIncDec(event
, limits
.min, -1000, 0)
416 limits
.max = valueIncDec(event
, limits
.max, 0, 1000)
418 limits
.offset
= valueIncDec(event
, limits
.offset
, -1000, 1000)
420 limits
.revert
= fieldIncDec(event
, limits
.revert
, 1)
422 model
.setOutput(servoPage
, limits
)
423 elseif event
== EVT_EXIT_BREAK
then
430 local function drawNextLine(x
, y
, label
, channel
)
431 lcd
.drawText(x
, y
, label
, 0);
432 lcd
.drawSource(x
+30, y
, MIXSRC_CH1
+channel
, 0)
441 local function drawConfirmationMenu()
445 lcd
.drawText(0, 1, "Ready to go?", 0);
446 lcd
.drawFilledRectangle(0, 0, LCD_W
, 9, 0)
447 if engineMode
== 1 then
448 x
, y
= drawNextLine(x
, y
, "Thr", thrCH1
)
450 if aileronsMode
== 1 then
451 x
, y
= drawNextLine(x
, y
, "Ail", ailCH1
)
452 elseif aileronsMode
== 2 then
453 x
, y
= drawNextLine(x
, y
, "AilL", ailCH1
)
454 x
, y
= drawNextLine(x
, y
, "AilR", ailCH2
)
456 if flapsMode
== 1 then
457 x
, y
= drawNextLine(x
, y
, "Flap", flapsCH1
)
458 elseif flapsMode
== 2 then
459 x
, y
= drawNextLine(x
, y
, "FlpL", flapsCH1
)
460 x
, y
= drawNextLine(x
, y
, "FlpR", flapsCH2
)
462 if brakesMode
== 1 then
463 x
, y
= drawNextLine(x
, y
, "Brak", brakesCH1
)
464 elseif brakesMode
== 2 then
465 x
, y
= drawNextLine(x
, y
, "BrkL", brakesCH1
)
466 x
, y
= drawNextLine(x
, y
, "BrkR", brakesCH2
)
468 if tailMode
== 3 then
469 x
, y
= drawNextLine(x
, y
, "VtaL", eleCH1
)
470 x
, y
= drawNextLine(x
, y
, "VtaR", eleCH2
)
472 x
, y
= drawNextLine(x
, y
, "Rud", rudCH1
)
473 if tailMode
== 1 then
474 x
, y
= drawNextLine(x
, y
, "Elev", eleCH1
)
475 elseif tailMode
== 2 then
476 x
, y
= drawNextLine(x
, y
, "EleL", eleCH1
)
477 x
, y
= drawNextLine(x
, y
, "EleR", eleCH2
)
480 lcd
.drawText(0, LCD_H
-8, "[Enter Long] to confirm", 0);
481 lcd
.drawFilledRectangle(0, LCD_H
-9, LCD_W
, 9, 0)
485 local function addMix(channel
, input
, name
, weight
, index
)
486 local mix
= { source
=input
, name
=name
}
487 if weight
~= nil then
493 model
.insertMix(channel
, index
, mix
)
496 local function applySettings()
497 model
.defaultInputs()
499 if engineMode
> 0 then
500 addMix(thrCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(2), "Engine")
502 if aileronsMode
== 1 then
503 addMix(ailCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(3), "Ail")
504 elseif aileronsMode
== 2 then
505 addMix(ailCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(3), "AilL")
506 addMix(ailCH2
, MIXSRC_FIRST_INPUT
+defaultChannel(3), "AilR", -100)
508 if flapsMode
== 1 then
509 addMix(flapsCH1
, MIXSRC_SA
, "Flap")
510 elseif flapsMode
== 2 then
511 addMix(flapsCH1
, MIXSRC_SA
, "FlapL")
512 addMix(flapsCH2
, MIXSRC_SA
, "FlapR")
514 if brakesMode
== 1 then
515 addMix(brakesCH1
, MIXSRC_SD
, "Brake")
516 elseif brakesMode
== 2 then
517 addMix(brakesCH1
, MIXSRC_SD
, "BrakeL")
518 addMix(brakesCH2
, MIXSRC_SD
, "BrakeR")
520 if tailMode
== 3 then
521 addMix(eleCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(1), "V-EleL", 50)
522 addMix(eleCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(0), "V-RudL", 50, 1)
523 addMix(eleCH2
, MIXSRC_FIRST_INPUT
+defaultChannel(1), "V-EleR", 50)
524 addMix(eleCH2
, MIXSRC_FIRST_INPUT
+defaultChannel(0), "V-RudR", -50, 1)
527 addMix(rudCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(0), "Rudder")
529 if tailMode
== 1 then
530 addMix(eleCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(1), "Elev")
531 elseif tailMode
== 2 then
532 addMix(eleCH1
, MIXSRC_FIRST_INPUT
+defaultChannel(1), "ElevG")
533 addMix(eleCH2
, MIXSRC_FIRST_INPUT
+defaultChannel(1), "ElevD")
538 local function confirmationMenu(event
)
541 drawConfirmationMenu()
544 navigate(event
, fieldsMax
, TAIL_PAGE
, page
)
546 if event
== EVT_EXIT_BREAK
then
548 elseif event
== EVT_ENTER_LONG
then
558 local function run(event
)
560 error("Cannot be run as a model script!")
563 if servoPage
~= nil then
565 elseif page
== ENGINE_PAGE
then
567 elseif page
== AILERONS_PAGE
then
569 elseif page
== FLAPERONS_PAGE
then
571 elseif page
== BRAKES_PAGE
then
573 elseif page
== TAIL_PAGE
then
575 elseif page
== CONFIRMATION_PAGE
then
576 return confirmationMenu(event
)
581 return { init
=init
, run
=run
}