Updated Wizard: reduced mixers name to 6 caracters.
[opentx.git] / radio / sdcard / taranis-x9 / SCRIPTS / WIZARD / multi.lua
blob5933b3b085c4c7514affea3bca6378c85cc323cb
1 ---- #########################################################################
2 ---- # #
3 ---- # Copyright (C) OpenTX #
4 -----# #
5 ---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
6 ---- # #
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. #
10 ---- # #
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. #
15 ---- # #
16 ---- #########################################################################
17 -- Multicopter Wizard pages
18 local THROTTLE_PAGE = 0
19 local ROLL_PAGE = 1
20 local PITCH_PAGE = 2
21 local YAW_PAGE = 3
22 local CONFIRMATION_PAGE = 4
24 -- Navigation variables
25 local page = THROTTLE_PAGE
26 local dirty = true
27 local edit = false
28 local field = 0
29 local fieldsMax = 0
31 -- Model settings
32 local thrCH1 = 0
33 local rollCH1 = 0
34 local yawCH1 = 0
35 local pitchCH1 = 0
37 -- Common functions
38 local lastBlink = 0
39 local function blinkChanged()
40 local time = getTime() % 128
41 local blink = (time - time % 64) / 64
42 if blink ~= lastBlink then
43 lastBlink = blink
44 return true
45 else
46 return false
47 end
48 end
50 local function fieldIncDec(event, value, max, force)
51 if edit or force==true then
52 if event == EVT_PLUS_BREAK or event == EVT_ROT_LEFT then
53 value = (value + max)
54 dirty = true
55 elseif event == EVT_MINUS_BREAK or event == EVT_ROT_RIGHT then
56 value = (value + max + 2)
57 dirty = true
58 end
59 value = (value % (max+1))
60 end
61 return value
62 end
64 local function valueIncDec(event, value, min, max)
65 if edit then
66 if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT or event == EVT_ROT_RIGHT then
67 if value < max then
68 value = (value + 1)
69 dirty = true
70 end
71 elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT or event == EVT_ROT_LEFT then
72 if value > min then
73 value = (value - 1)
74 dirty = true
75 end
76 end
77 end
78 return value
79 end
81 local function navigate(event, fieldMax, prevPage, nextPage)
82 if event == EVT_ENTER_BREAK then
83 edit = not edit
84 dirty = true
85 elseif edit then
86 if event == EVT_EXIT_BREAK then
87 edit = false
88 dirty = true
89 elseif not dirty then
90 dirty = blinkChanged()
91 end
92 else
93 if event == EVT_PAGE_BREAK then
94 page = nextPage
95 field = 0
96 dirty = true
97 elseif event == EVT_PAGE_LONG then
98 page = prevPage
99 field = 0
100 killEvents(event);
101 dirty = true
102 else
103 field = fieldIncDec(event, field, fieldMax, true)
108 local function getFieldFlags(position)
109 flags = 0
110 if field == position then
111 flags = INVERS
112 if edit then
113 flags = INVERS + BLINK
116 return flags
119 local function channelIncDec(event, value)
120 if not edit and event==EVT_MENU_BREAK then
121 servoPage = value
122 dirty = true
123 else
124 value = valueIncDec(event, value, 0, 15)
126 return value
129 -- Init function
130 local function init()
131 thrCH1 = defaultChannel(2)
132 rollCH1 = defaultChannel(3)
133 yawCH1 = defaultChannel(0)
134 pitchCH1 = defaultChannel(1)
137 -- Throttle Menu
138 local function drawThrottleMenu()
139 lcd.clear()
140 lcd.drawText(1, 0, "Select multicopter throttle channel", 0)
141 lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
142 lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
143 lcd.drawPixmap(120, 8, "multi-thr.bmp")
144 lcd.drawText(25, LCD_H-16, "Assign channel", 0);
145 lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
146 lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(0))
147 fieldsMax = 0
150 local function throttleMenu(event)
151 if dirty then
152 dirty = false
153 drawThrottleMenu()
155 navigate(event, fieldsMax, page, page+1)
156 thrCH1 = channelIncDec(event, thrCH1)
159 -- Roll Menu
160 local function drawRollMenu()
161 lcd.clear()
162 lcd.drawText(1, 0, "Select multicopter roll channel", 0)
163 lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
164 lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
165 lcd.drawPixmap(120, 8, "multi-roll.bmp")
166 lcd.drawText(25, LCD_H-16, "Assign channel", 0);
167 lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
168 lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+rollCH1, getFieldFlags(0))
169 fieldsMax = 0
172 local function rollMenu(event)
173 if dirty then
174 dirty = false
175 drawRollMenu()
177 navigate(event, fieldsMax, page-1, page+1)
178 rollCH1 = channelIncDec(event, rollCH1)
181 -- Pitch Menu
182 local function drawPitchMenu()
183 lcd.clear()
184 lcd.drawText(1, 0, "Select multicopter pitch channel", 0)
185 lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
186 lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
187 lcd.drawPixmap(120, 8, "multi-pitch.bmp")
188 lcd.drawText(25, LCD_H-16, "Assign channel", 0);
189 lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
190 lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+pitchCH1, getFieldFlags(0))
191 fieldsMax = 0
194 local function pitchMenu(event)
195 if dirty then
196 dirty = false
197 drawPitchMenu()
199 navigate(event, fieldsMax, page-1, page+1)
200 pitchCH1 = channelIncDec(event, pitchCH1)
203 -- Yaw Menu
204 local function drawYawMenu()
205 lcd.clear()
206 lcd.drawText(1, 0, "Select multicopter yaw channel", 0)
207 lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE)
208 lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H-1, DOTTED, 0)
209 lcd.drawPixmap(120, 8, "multi-yaw.bmp")
210 lcd.drawText(25, LCD_H-16, "Assign channel", 0);
211 lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0);
212 lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+yawCH1, getFieldFlags(0))
213 fieldsMax = 0
216 local function yawMenu(event)
217 if dirty then
218 dirty = false
219 drawYawMenu()
221 navigate(event, fieldsMax, page-1, page+1)
222 yawCH1 = channelIncDec(event, yawCH1)
225 -- Confirmation Menu
226 local function drawNextLine(x, y, label, channel)
227 lcd.drawText(x, y, label, 0);
228 lcd.drawText(x+48, y, ":", 0);
229 lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0)
230 y = y + 8
231 if y > 50 then
232 y = 12
233 x = 120
235 return x, y
238 local function drawConfirmationMenu()
239 local x = 22
240 local y = 12
241 lcd.clear()
242 lcd.drawText(48, 1, "Ready to go?", 0);
243 lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0)
244 x, y = drawNextLine(x, y, "Throttle", thrCH1)
245 x, y = drawNextLine(x, y, "Roll", rollCH1)
246 x, y = drawNextLine(x, y, "Pitch", pitchCH1)
247 x, y = drawNextLine(x, y, "Yaw", yawCH1)
248 lcd.drawText(48, LCD_H-8, "Long [ENT] to confirm", 0);
249 lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0)
250 lcd.drawPixmap(LCD_W-18, LCD_H-17, "confirm-tick.bmp")
251 fieldsMax = 0
254 local function addMix(channel, input, name, weight, index)
255 local mix = { source=input, name=name }
256 if weight ~= nil then
257 mix.weight = weight
259 if index == nil then
260 index = 0
262 model.insertMix(channel, index, mix)
265 local function applySettings()
266 model.defaultInputs()
267 model.deleteMixes()
268 addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Engine")
269 addMix(rollCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Roll")
270 addMix(yawCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Yaw")
271 addMix(pitchCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch")
274 local function confirmationMenu(event)
275 if dirty then
276 dirty = false
277 drawConfirmationMenu()
280 navigate(event, fieldsMax, YAW_PAGE, page)
282 if event == EVT_EXIT_BREAK then
283 return 2
284 elseif event == EVT_ENTER_LONG then
285 killEvents(event)
286 applySettings()
287 return 2
288 else
289 return 0
293 -- Main
294 local function run(event)
295 if event == nil then
296 error("Cannot be run as a model script!")
298 if page == THROTTLE_PAGE then
299 throttleMenu(event)
300 elseif page == ROLL_PAGE then
301 rollMenu(event)
302 elseif page == YAW_PAGE then
303 yawMenu(event)
304 elseif page == PITCH_PAGE then
305 pitchMenu(event)
306 elseif page == CONFIRMATION_PAGE then
307 return confirmationMenu(event)
309 return 0
312 return { init=init, run=run }