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 ---- #########################################################################
25 local refreshState
= 0
26 local refreshIndex
= 0
27 local calibrationState
= 0
29 local calibrationStep
= 0
32 local modifications
= {}
33 local positionConfirmed
= 0
34 local orientationAutoSense
= 0
36 local calibrationFields
= {
37 {"X:", VALUE
, 0x9E, 0, -100, 100, "%"},
38 {"Y:", VALUE
, 0x9F, 0, -100, 100, "%"},
39 {"Z:", VALUE
, 0xA0, 0, -100, 100, "%"}
42 local function drawProgressBar()
43 local width
= (140 * refreshIndex
) / #fields
44 lcd
.drawRectangle(30, 1, 144, 6)
45 lcd
.drawFilledRectangle(32, 3, width
, 2);
48 -- Select the next or previous page
49 local function selectPage(step
)
50 page
= 1 + ((page
+ step
- 1 + #pages
) % #pages
)
56 -- Draw initial warning page
57 local function runWarningPage(event
)
59 lcd
.drawScreenTitle("S6R Calibration", page
, #pages
)
60 lcd
.drawText(0, 10, "You only need to calibrate", SMLSIZE
)
61 lcd
.drawText(0, 20, "once. You will need the S6R,", SMLSIZE
)
62 lcd
.drawText(0, 30, "power, and a level surface.", SMLSIZE
)
63 lcd
.drawText(0, 40, "Press [Enter] when ready", SMLSIZE
)
64 lcd
.drawText(0, 50, "Press [Exit] to cancel", SMLSIZE
)
65 if event
== EVT_ENTER_BREAK
then
68 elseif event
== EVT_EXIT_BREAK
then
74 -- Redraw the current page
75 local function redrawFieldsPage()
77 lcd
.drawScreenTitle("S6R Calibration", page
, #pages
)
79 if refreshIndex
< #fields
then
83 for index
= 1, 7, 1 do
84 local field
= fields
[pageOffset
+index
]
89 local attr
= current
== (pageOffset
+index
) and ((edit
== true and BLINK
or 0) + INVERS
) or 0
91 lcd
.drawText(0, 1+8*index
, field
[1])
93 if field
[4] == nil then
94 lcd
.drawText(COLUMN_2
, 1+8*index
, "---", attr
)
96 if field
[2] == VALUE
then
97 lcd
.drawNumber(COLUMN_2
, 1+8*index
, field
[4], LEFT
+ attr
)
98 elseif field
[2] == COMBO
then
99 if field
[4] >= 0 and field
[4] < #(field
[5]) then
100 lcd
.drawText(COLUMN_2
, 1+8*index
, field
[5][1+field
[4]]
, attr
)
107 local function telemetryRead(field
)
108 return sportTelemetryPush(0x17, 0x30, 0x0C30, field
)
111 local function telemetryWrite(field
, value
)
112 return sportTelemetryPush(0x17, 0x31, 0x0C30, field
+ value
*256)
115 local telemetryPopTimeout
= 0
116 local function refreshNext()
117 if refreshState
== 0 then
118 if calibrationState
== 1 then
119 if telemetryWrite(0x9D, calibrationStep
) == true then
122 telemetryPopTimeout
= getTime() + 80 -- normal delay is 500ms
124 elseif #modifications
> 0 then
125 telemetryWrite(modifications
[1][1], modifications
[1][2])
126 modifications
[1] = nil
127 elseif refreshIndex
< #fields
then
128 local field
= fields
[refreshIndex
+ 1]
129 if telemetryRead(field
[3]) == true then
131 telemetryPopTimeout
= getTime() + 80 -- normal delay is 500ms
134 elseif refreshState
== 1 then
135 local physicalId
, primId
, dataId
, value
= sportTelemetryPop()
136 if physicalId
== 0x1A and primId
== 0x32 and dataId
== 0x0C30 then
137 local fieldId
= value
% 256
138 if calibrationState
== 2 then
139 if fieldId
== 0x9D then
142 calibrationStep
= (calibrationStep
+ 1) % 7
145 local field
= fields
[refreshIndex
+ 1]
146 if fieldId
== field
[3] then
147 local value
= math
.floor(value
/ 256)
148 if field
[3] >= 0x9E and field
[3] <= 0xA0 then
149 local b1
= value
% 256
150 local b2
= math
.floor(value
/ 256)
152 value
= value
- bit32
.band(value
, 0x8000) * 2
154 if field
[2] == COMBO
and #field
== 6 then
155 for index
= 1, #(field
[6]), 1 do
156 if value
== field
[6][index
] then
161 elseif field
[2] == VALUE
and #field
== 8 then
162 value
= value
- field
[8] + field
[5]
164 fields
[refreshIndex
+ 1][4] = value
165 refreshIndex
= refreshIndex
+ 1
169 elseif getTime() > telemetryPopTimeout
then
176 local function updateField(field
)
177 local value
= field
[4]
178 if field
[2] == COMBO
and #field
== 6 then
179 value
= field
[6][1+value
]
180 elseif field
[2] == VALUE
and #field
== 8 then
181 value
= value
+ field
[8] - field
[5]
183 modifications
[#modifications
+1] = { field
[3], value
}
187 local function runFieldsPage(event
)
188 if event
== EVT_EXIT_BREAK
then -- exit script
190 elseif event
== EVT_ENTER_BREAK
then -- toggle editing/selecting current field
191 if fields
[current
][4] ~= nil then
193 if edit
== false then
194 updateField(fields
[current
])
198 if event
== EVT_PLUS_FIRST
or event
== EVT_ROT_RIGHT
or event
== EVT_PLUS_REPT
then
200 elseif event
== EVT_MINUS_FIRST
or event
== EVT_ROT_LEFT
or event
== EVT_MINUS_REPT
then
204 if event
== EVT_MINUS_FIRST
or event
== EVT_ROT_LEFT
then
206 elseif event
== EVT_PLUS_FIRST
or event
== EVT_ROT_RIGHT
then
214 local function drawCalibrationOrientation(x
, y
, step
)
215 local orientation
= { {"Label up.", "", 0, 0, 1000, 0, 0, 1000},
216 {"Label down.", "", 0, 0, -1000, 0, 0, -1000},
217 {"Pins Up.", "", -1000, 0, 0, 1000, 0, 0},
218 {"Pins Down.", "", 1000, 0, 0, -1000, 0, 0},
219 {"Label facing you", "Pins Right", 0, 1000, 0, 0, -1000, 0},
220 {"Label facing you", "Pins Left", 0, -1000 , 0, 0, 1000, 0} }
222 lcd
.drawText(0, 9, "Place the S6R as follows:", 0)
223 lcd
.drawText(x
-9, y
, orientation
[step
][1])
224 lcd
.drawText(x
-9, y
+10, orientation
[step
][2])
225 local positionStatus
= 0
226 for index
= 1, 3, 1 do
227 local field
= fields
[index
]
228 lcd
.drawText(90, 12+10*index
, field
[1], 0)
229 if math
.abs(field
[4] - orientation
[step
][2+index
+orientationAutoSense
]) < 200 then
230 lcd
.drawNumber(100, 12+10*index
, field
[4]/10, LEFT
+PREC2
)
231 positionStatus
= positionStatus
+ 1
233 lcd
.drawNumber(100, 12+10*index
, field
[4]/10, LEFT
+PREC2
+INVERS
)
236 if step
== 3 and positionStatus
== 2 then -- orientation auto sensing
237 orientationAutoSense
= 3 - orientationAutoSense
239 if positionStatus
== 3 then
240 lcd
.drawText(0, 56, " [Enter] to validate ", INVERS
)
241 positionConfirmed
= 1
245 local function runCalibrationPage(event
)
246 fields
= calibrationFields
247 if refreshIndex
== #fields
then
251 lcd
.drawScreenTitle("S6R Calibration", page
, #pages
)
252 if(calibrationStep
< 6) then
253 drawCalibrationOrientation(10, 24, 1 + calibrationStep
)
255 local attr
= calibrationState
== 0 and INVERS
or 0
256 --lcd.drawText(0, 56, "[Enter] to validate", attr)
258 lcd
.drawText(0, 19, "Calibration completed", 0)
259 -- lcd.drawText(10, 19, "Done",0)
260 lcd
.drawText(0, 56, "Press [Exit] when ready", attr
)
262 if calibrationStep
> 6 and (event
== EVT_ENTER_BREAK
or event
== EVT_EXIT_BREAK
) then
264 elseif event
== EVT_ENTER_BREAK
and positionConfirmed
then
266 positionConfirmed
= 0
273 local function init()
274 current
, edit
, refreshState
, refreshIndex
= 1, false, 0, 0
282 local function run(event
)
284 error("Cannot be run as a model script!")
286 elseif event
== EVT_PAGE_BREAK
then
288 elseif event
== EVT_PAGE_LONG
then
293 local result
= pages
[page
](event
)
299 return { init
=init
, run
=run
}