2 -- An FRSKY S.Port <passthrough protocol> based Telemetry script for Taranis X9D+
4 -- Copyright (C) 2018. Alessandro Apostoli
5 -- https://github.com/yaapu
7 -- This program is free software; you can redistribute it and/or modify
8 -- it under the terms of the GNU General Public License as published by
9 -- the Free Software Foundation; either version 3 of the License, or
10 -- (at your option) any later version.
12 -- This program is distributed in the hope that it will be useful,
13 -- but WITHOUT ANY WARRANTY, without even the implied warranty of
14 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 -- GNU General Public License for more details.
17 -- You should have received a copy of the GNU General Public License
18 -- along with this program; if not, see <http://www.gnu.org/licenses>.
20 -- Passthrough protocol reference:
21 -- https://cdn.rawgit.com/ArduPilot/ardupilot_wiki/33cd0c2c/images/FrSky_Passthrough_protocol.xlsx
23 -- Borrowed some code from the LI-xx BATTCHECK v3.30 script
24 -- http://frskytaranis.forumactif.org/t2800-lua-download-un-testeur-de-batterie-sur-la-radio
27 local cellfull
, cellempty
= 4.2, 3.00
28 local cell
= {0, 0, 0, 0, 0 ,0}
29 local cellsumfull
, cellsumempty
, cellsumtype
, cellsum
= 0, 0, 0, 0
31 local i
, cellmin
, cellresult
= 0, cellfull
, 0, 0
36 MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */
37 MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */
38 MAV_TYPE_QUADROTOR=2, /* Quadrotor | */
39 MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */
40 MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */
41 MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */
42 MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */
43 MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */
44 MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */
45 MAV_TYPE_ROCKET=9, /* Rocket | */
46 MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */
47 MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */
48 MAV_TYPE_SUBMARINE=12, /* Submarine | */
49 MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */
50 MAV_TYPE_OCTOROTOR=14, /* Octorotor | */
51 MAV_TYPE_TRICOPTER=15, /* Tricopter | */
52 MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */
53 MAV_TYPE_KITE=17, /* Kite | */
54 MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */
55 MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */
56 MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */
57 MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */
58 MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */
59 MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */
60 MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */
61 MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */
62 MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */
63 MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */
64 MAV_TYPE_PARAFOIL=28, /* Steerable, nonrigid airfoil | */
65 MAV_TYPE_DODECAROTOR=29, /* Dodecarotor | */
69 frameTypes
[0] = "copter"
70 frameTypes
[1] = "plane"
71 frameTypes
[2] = "copter"
72 frameTypes
[3] = "copter"
73 frameTypes
[4] = "copter"
79 frameTypes
[10] = "rover"
80 frameTypes
[11] = "boat"
82 frameTypes
[13] = "copter"
83 frameTypes
[14] = "copter"
84 frameTypes
[15] = "copter"
85 frameTypes
[16] = "plane"
88 frameTypes
[19] = "plane"
89 frameTypes
[20] = "plane"
90 frameTypes
[21] = "plane"
91 frameTypes
[22] = "plane"
92 frameTypes
[23] = "plane"
93 frameTypes
[24] = "plane"
94 frameTypes
[25] = "plane"
97 frameTypes
[28] = "plane"
98 frameTypes
[29] = "copter"
101 local flightModes
= {}
102 flightModes
["copter"] = {}
103 flightModes
["plane"] = {}
104 flightModes
["rover"] = {}
105 -- copter flight modes
106 flightModes
["copter"][0]=""
107 flightModes
["copter"][1]="Stabilize"
108 flightModes
["copter"][2]="Acro"
109 flightModes
["copter"][3]="AltHold"
110 flightModes
["copter"][4]="Auto"
111 flightModes
["copter"][5]="Guided"
112 flightModes
["copter"][6]="Loiter"
113 flightModes
["copter"][7]="RTL"
114 flightModes
["copter"][8]="Circle"
115 flightModes
["copter"][9]=""
116 flightModes
["copter"][10]="Land"
117 flightModes
["copter"][11]=""
118 flightModes
["copter"][12]="Drift"
119 flightModes
["copter"][13]=""
120 flightModes
["copter"][14]="Sport"
121 flightModes
["copter"][15]="Flip"
122 flightModes
["copter"][16]="AutoTune"
123 flightModes
["copter"][17]="PosHold"
124 flightModes
["copter"][18]="Brake"
125 flightModes
["copter"][19]="Throw"
126 flightModes
["copter"][20]="Avoid ADSB"
127 flightModes
["copter"][21]="Guided NO GPS"
128 -- plane flight modes
129 flightModes
["plane"][0]="Manual"
130 flightModes
["plane"][1]="Circle"
131 flightModes
["plane"][2]="Stabilize"
132 flightModes
["plane"][3]="Training"
133 flightModes
["plane"][4]="Acro"
134 flightModes
["plane"][5]="FlyByWireA"
135 flightModes
["plane"][6]="FlyByWireB"
136 flightModes
["plane"][7]="Cruise"
137 flightModes
["plane"][8]="Autotune"
138 flightModes
["plane"][9]=""
139 flightModes
["plane"][10]="Auto"
140 flightModes
["plane"][11]="RTL"
141 flightModes
["plane"][12]="Loiter"
142 flightModes
["plane"][13]=""
143 flightModes
["plane"][14]="Avoid ADSB"
144 flightModes
["plane"][15]="Guided"
145 flightModes
["plane"][16]="Initializing"
146 flightModes
["plane"][17]="QStabilize"
147 flightModes
["plane"][18]="QHover"
148 flightModes
["plane"][19]="QLoiter"
149 flightModes
["plane"][20]="Qland"
150 flightModes
["plane"][21]="QRTL"
151 -- rover flight modes
152 flightModes
["rover"][0]="Manual"
153 flightModes
["rover"][1]="Acro"
154 flightModes
["rover"][2]=""
155 flightModes
["rover"][3]="Steering"
156 flightModes
["rover"][4]="Hold"
157 flightModes
["rover"][5]=""
158 flightModes
["rover"][6]=""
159 flightModes
["rover"][7]=""
160 flightModes
["rover"][8]=""
161 flightModes
["rover"][9]=""
162 flightModes
["rover"][10]="Auto"
163 flightModes
["rover"][11]="RTL"
164 flightModes
["rover"][12]="SmartRTL"
165 flightModes
["rover"][13]=""
166 flightModes
["rover"][14]=""
167 flightModes
["rover"][15]="Guided"
168 flightModes
["rover"][16]="Initializing"
169 flightModes
["rover"][17]=""
170 flightModes
["rover"][18]=""
171 flightModes
["rover"][19]=""
172 flightModes
["rover"][20]=""
173 flightModes
["rover"][21]=""
175 local soundFileBasePath
= "/SOUNDS/yaapu0/en"
176 local soundFiles
= {}
178 soundFiles
["bat5"] = "bat5.wav"
179 soundFiles
["bat10"] = "bat10.wav"
180 soundFiles
["bat15"] = "bat15.wav"
181 soundFiles
["bat20"] = "bat20.wav"
182 soundFiles
["bat25"] = "bat25.wav"
183 soundFiles
["bat30"] = "bat30.wav"
184 soundFiles
["bat40"] = "bat40.wav"
185 soundFiles
["bat50"] = "bat50.wav"
186 soundFiles
["bat60"] = "bat60.wav"
187 soundFiles
["bat70"] = "bat70.wav"
188 soundFiles
["bat80"] = "bat80.wav"
189 soundFiles
["bat90"] = "bat90.wav"
191 soundFiles
["gpsfix"] = "gpsfix.wav"
192 soundFiles
["gpsnofix"] = "gpsnofix.wav"
194 soundFiles
["lowbat"] = "lowbat.wav"
195 soundFiles
["ekf"] = "ekf.wav"
197 soundFiles
["yaapu"] = "yaapu.wav"
198 soundFiles
["landing"] = "landing.wav"
199 soundFiles
["armed"] = "armed.wav"
200 soundFiles
["disarmed"] = "disarmed.wav"
202 local soundFilesByFrameTypeAndFlightMode
= {}
203 soundFilesByFrameTypeAndFlightMode
["copter"] = {}
204 soundFilesByFrameTypeAndFlightMode
["plane"] = {}
205 soundFilesByFrameTypeAndFlightMode
["rover"] = {}
207 soundFilesByFrameTypeAndFlightMode
["copter"][0]=""
208 soundFilesByFrameTypeAndFlightMode
["copter"][1]="stabilize.wav"
209 soundFilesByFrameTypeAndFlightMode
["copter"][2]="acro.wav"
210 soundFilesByFrameTypeAndFlightMode
["copter"][3]="althold.wav"
211 soundFilesByFrameTypeAndFlightMode
["copter"][4]="auto.wav"
212 soundFilesByFrameTypeAndFlightMode
["copter"][5]="guided.wav"
213 soundFilesByFrameTypeAndFlightMode
["copter"][6]="loiter.wav"
214 soundFilesByFrameTypeAndFlightMode
["copter"][7]="rtl.wav"
215 soundFilesByFrameTypeAndFlightMode
["copter"][8]="circle.wav"
216 soundFilesByFrameTypeAndFlightMode
["copter"][9]=""
217 soundFilesByFrameTypeAndFlightMode
["copter"][10]="land.wav"
218 soundFilesByFrameTypeAndFlightMode
["copter"][11]=""
219 soundFilesByFrameTypeAndFlightMode
["copter"][12]="drift.wav"
220 soundFilesByFrameTypeAndFlightMode
["copter"][13]=""
221 soundFilesByFrameTypeAndFlightMode
["copter"][14]="sport.wav"
222 soundFilesByFrameTypeAndFlightMode
["copter"][15]="flip.wav"
223 soundFilesByFrameTypeAndFlightMode
["copter"][16]="loiter.wav"
224 soundFilesByFrameTypeAndFlightMode
["copter"][17]="poshold.wav"
225 soundFilesByFrameTypeAndFlightMode
["copter"][18]="brake"
226 soundFilesByFrameTypeAndFlightMode
["copter"][19]="throw.wav"
227 soundFilesByFrameTypeAndFlightMode
["copter"][20]="avoidadbs"
228 soundFilesByFrameTypeAndFlightMode
["copter"][21]="guidednogps"
230 soundFilesByFrameTypeAndFlightMode
["plane"][0]="manual.wav"
231 soundFilesByFrameTypeAndFlightMode
["plane"][1]="circle.wav"
232 soundFilesByFrameTypeAndFlightMode
["plane"][2]="stabilize.wav"
233 soundFilesByFrameTypeAndFlightMode
["plane"][3]="training.wav"
234 soundFilesByFrameTypeAndFlightMode
["plane"][4]="acro.wav"
235 soundFilesByFrameTypeAndFlightMode
["plane"][5]="flybywirea.wav"
236 soundFilesByFrameTypeAndFlightMode
["plane"][6]="flybywireb.wav"
237 soundFilesByFrameTypeAndFlightMode
["plane"][7]="cruise.wav"
238 soundFilesByFrameTypeAndFlightMode
["plane"][8]="autotune.wav"
239 soundFilesByFrameTypeAndFlightMode
["plane"][9]=""
240 soundFilesByFrameTypeAndFlightMode
["plane"][10]="auto.wav"
241 soundFilesByFrameTypeAndFlightMode
["plane"][11]="rtl.wav"
242 soundFilesByFrameTypeAndFlightMode
["plane"][12]="loiter.wav"
243 soundFilesByFrameTypeAndFlightMode
["plane"][13]=""
244 soundFilesByFrameTypeAndFlightMode
["plane"][14]="avoidadbs"
245 soundFilesByFrameTypeAndFlightMode
["plane"][15]="guided.wav"
246 soundFilesByFrameTypeAndFlightMode
["plane"][16]="initializing.wav"
247 soundFilesByFrameTypeAndFlightMode
["plane"][17]="qstabilize.wav"
248 soundFilesByFrameTypeAndFlightMode
["plane"][18]="qhover.wav"
249 soundFilesByFrameTypeAndFlightMode
["plane"][19]="qloiter.wav"
250 soundFilesByFrameTypeAndFlightMode
["plane"][20]="qland.wav"
251 soundFilesByFrameTypeAndFlightMode
["plane"][21]="qrtl.wav"
253 soundFilesByFrameTypeAndFlightMode
["rover"][0]="manual_r.wav"
254 soundFilesByFrameTypeAndFlightMode
["rover"][1]="acro_r.wav"
255 soundFilesByFrameTypeAndFlightMode
["rover"][2]=""
256 soundFilesByFrameTypeAndFlightMode
["rover"][3]="steering_r.wav"
257 soundFilesByFrameTypeAndFlightMode
["rover"][4]="hold_r.wav"
258 soundFilesByFrameTypeAndFlightMode
["rover"][5]=""
259 soundFilesByFrameTypeAndFlightMode
["rover"][6]=""
260 soundFilesByFrameTypeAndFlightMode
["rover"][7]=""
261 soundFilesByFrameTypeAndFlightMode
["rover"][8]=""
262 soundFilesByFrameTypeAndFlightMode
["rover"][9]=""
263 soundFilesByFrameTypeAndFlightMode
["rover"][10]="auto_r.wav"
264 soundFilesByFrameTypeAndFlightMode
["rover"][11]="rtl_r.wav"
265 soundFilesByFrameTypeAndFlightMode
["rover"][12]="smartrtl_r.wav"
266 soundFilesByFrameTypeAndFlightMode
["rover"][13]=""
267 soundFilesByFrameTypeAndFlightMode
["rover"][14]=""
268 soundFilesByFrameTypeAndFlightMode
["rover"][15]="guided_r.wav"
269 soundFilesByFrameTypeAndFlightMode
["rover"][16]="initializing.wav"
270 soundFilesByFrameTypeAndFlightMode
["rover"][17]=""
271 soundFilesByFrameTypeAndFlightMode
["rover"][18]=""
272 soundFilesByFrameTypeAndFlightMode
["rover"][19]=""
273 soundFilesByFrameTypeAndFlightMode
["rover"][20]=""
274 soundFilesByFrameTypeAndFlightMode
["rover"][21]=""
277 local gpsStatuses
= {}
278 gpsStatuses
[0]="NoGPS"
279 gpsStatuses
[1]="NoLock"
280 gpsStatuses
[2]="2DFIX"
281 gpsStatuses
[3]="3DFix"
283 local mavSeverity
= {}
296 local landComplete
= 0
297 local statusArmed
= 0
298 local batteryFailsafe
= 0
299 local lastBatteryFailsafe
= 0
300 local ekfFailsafe
= 0
301 local lastEkfFailsafe
= 0
309 local battCurrent
= 0
313 local battCurrent2
= 0
320 local messageBuffer
= ""
321 local messageHistory
= {}
324 local messageDuplicate
= 1
325 local lastMessage
= ""
326 local lastMessageValue
= 0
327 local lastMessageTime
= 0
336 local SENSOR_ID
,FRAME_ID
,DATA_ID
,VALUE
340 local paramId
,paramValue
342 local battFailsafeVoltage
= 0
343 local battFailsafeCapacity
= 0
344 local battCapacity
= 0
351 local noTelemetryData
= 1
353 local function playSound(soundFile
)
354 playFile(soundFileBasePath
.. "/" .. soundFiles
[soundFile
])
357 local function playSoundByFrameTypeAndFlightMode(frameType
,flightMode
)
358 playFile(soundFileBasePath
.. "/" .. soundFilesByFrameTypeAndFlightMode
[frameTypes
[frameType]]
[flightMode
])
361 local function getValueOrDefault(value
)
362 local tmp
= getValue(value
)
369 local function pushMessage(severity
, msg
)
370 if ( severity
< 4) then
376 if msg
== lastMessage
then
377 messageDuplicate
= messageDuplicate
+ 1
378 if messageDuplicate
> 1 then
379 if string.len(mm
) > 33 then
380 mm
= string.sub(mm
,1,33)
381 messageHistory
[messageIdx
- 1] = string.format("[%02d:%s] %-33s (x%d)", messageIdx
- 1, mavSeverity
[severity
], mm
, messageDuplicate
)
383 messageHistory
[messageIdx
- 1] = string.format("[%02d:%s] %s (x%d)", messageIdx
- 1, mavSeverity
[severity
], msg
, messageDuplicate
)
387 messageHistory
[messageIdx
] = string.format("[%02d:%s] %s", messageIdx
, mavSeverity
[severity
], msg
)
388 messageIdx
= messageIdx
+ 1
392 lastMessageTime
= getTime() -- valore in secondi
395 local function logTelemetryToFile(S_ID
,F_ID
,D_ID
,VA
)
412 local logFile
= io
.open("yaapu.log","a")
413 io
.write(logFile
,string.format("%d,%#04x,%#04x,%#04x,%#04x", getTime(), lc1
, lc2
, lc3
, lc4
),"\r\n")
418 local lastTimerStart
= 0
420 local function startTimer()
421 lastTimerStart
= getTime()/100
424 local function stopTimer()
425 seconds
= seconds
+ getTime()/100 - lastTimerStart
429 local function symTimer()
430 thrOut
= getValue("thr")
431 if (thrOut
> -500 ) then
438 local function symGPS()
439 thrOut
= getValue("thr")
440 if (thrOut
> 0 ) then
448 elseif thrOut
> -500 then
467 local function symFrameType()
468 local ch11
= getValue("ch11")
469 if (ch11
< -300) then
471 elseif ch11
< 300 then
478 local function symBatt()
479 thrOut
= getValue("thr")
480 if (thrOut
> 0 ) then
481 LIPObatt
= 1350 + ((thrOut
)*0.01 * 30)
482 LIPOcelm
= LIPObatt
/4
483 battCurrent
= 100 + ((thrOut
)*0.01 * 30)
484 battVolt
= LIPObatt
*0.1
486 battMah
= math
.abs(1000*(thrOut
/200))
487 flightMode
= math
.floor(20 * math
.abs(thrOut
)*0.001)
491 -- simulates attitude by using channel 1 for roll, channel 2 for pitch and channel 4 for yaw
492 local function symAttitude()
496 -- roll [-1024,1024] ==> [-180,180]
497 rollCh
= getValue("ch1") * 0.175
498 -- pitch [1024,-1024] ==> [-90,90]
499 pitchCh
= getValue("ch2") * 0.0878
500 -- yaw [-1024,1024] ==> [0,360]
501 yawCh
= getValue("ch10")
502 if ( yawCh
>= 0) then
503 yawCh
= yawCh
* 0.175
505 yawCh
= 360 + (yawCh
* 0.175)
512 local function symHome()
515 -- home angle in deg [0-360]
516 S2Ch
= getValue("ch12")
517 yawCh
= getValue("ch4")
520 if ( yawCh
>= 0) then
521 yawCh
= yawCh
* 0.175
523 yawCh
= 360 + (yawCh
* 0.175)
528 S2Ch
= 360 + (S2Ch
* 0.175)
530 if (thrOut
> 0 ) then
538 local function processTelemetry()
539 SENSOR_ID
,FRAME_ID
,DATA_ID
,VALUE
= sportTelemetryPop()
549 if ( FRAME_ID
== 0x10) then
551 -- logTelemetryToFile(SENSOR_ID,FRAME_ID,DATA_ID,VALUE)
554 if ( DATA_ID
== 0x5006) then -- ROLLPITCH
555 -- roll [0,1800] ==> [-180,180]
556 roll
= (bit32
.extract(VALUE
,0,11) - 900) * 0.2
557 -- pitch [0,900] ==> [-90,90]
558 pitch
= (bit32
.extract(VALUE
,11,10) - 450) * 0.2
559 elseif ( DATA_ID
== 0x5005) then -- VELANDYAW
560 vSpeed
= bit32
.extract(VALUE
,1,7) * (10^bit32
.extract(VALUE
,0,1))
561 if (bit32
.extract(VALUE
,8,1) == 1) then
564 hSpeed
= bit32
.extract(VALUE
,10,7) * (10^bit32
.extract(VALUE
,9,1))
565 yaw
= bit32
.extract(VALUE
,17,11) * 0.2
566 elseif ( DATA_ID
== 0x5001) then -- AP STATUS
567 flightMode
= bit32
.extract(VALUE
,0,5)
568 simpleMode
= bit32
.extract(VALUE
,5,2)
569 landComplete
= bit32
.extract(VALUE
,7,1)
570 statusArmed
= bit32
.extract(VALUE
,8,1)
571 batteryFailsafe
= bit32
.extract(VALUE
,9,1)
572 ekfFailsafe
= bit32
.extract(VALUE
,10,2)
573 elseif ( DATA_ID
== 0x5002) then -- GPS STATUS
574 numSats
= bit32
.extract(VALUE
,0,4)
575 gpsStatus
= bit32
.extract(VALUE
,4,2)
576 gpsHdopC
= bit32
.extract(VALUE
,7,7) * (10^bit32
.extract(VALUE
,6,1)) -- dm
577 gpsAlt
= bit32
.extract(VALUE
,24,7) * (10^bit32
.extract(VALUE
,22,2)) -- dm
578 if (bit32
.extract(VALUE
,31,1) == 1) then
581 elseif ( DATA_ID
== 0x5003) then -- BATT
582 battVolt
= bit32
.extract(VALUE
,0,9)
583 battCurrent
= bit32
.extract(VALUE
,10,7) * (10^bit32
.extract(VALUE
,9,1))
584 battMah
= bit32
.extract(VALUE
,17,15)
585 elseif ( DATA_ID
== 0x5008) then -- BATT2
586 battVolt2
= bit32
.extract(VALUE
,0,9)
587 battCurrent2
= bit32
.extract(VALUE
,10,7) * (10^bit32
.extract(VALUE
,9,1))
588 battMah2
= bit32
.extract(VALUE
,17,15)
589 elseif ( DATA_ID
== 0x5004) then -- HOME
590 homeDist
= bit32
.extract(VALUE
,2,10) * (10^bit32
.extract(VALUE
,0,2))
591 homeAlt
= bit32
.extract(VALUE
,14,10) * (10^bit32
.extract(VALUE
,12,2)) * 0.1
592 if (bit32
.extract(VALUE
,24,1) == 1) then
593 homeAlt
= homeAlt
* -1
595 homeAngle
= bit32
.extract(VALUE
, 25, 7) * 3
596 elseif ( DATA_ID
== 0x5000) then -- MESSAGES
597 if (VALUE
~= lastMessageValue
) then
598 lastMessageValue
= VALUE
599 c1
= bit32
.extract(VALUE
,0,7)
600 c2
= bit32
.extract(VALUE
,8,7)
601 c3
= bit32
.extract(VALUE
,16,7)
602 c4
= bit32
.extract(VALUE
,24,7)
603 messageBuffer
= messageBuffer
.. string.char(c4
)
604 messageBuffer
= messageBuffer
.. string.char(c3
)
605 messageBuffer
= messageBuffer
.. string.char(c2
)
606 messageBuffer
= messageBuffer
.. string.char(c1
)
607 if (c1
== 0 or c2
== 0 or c3
== 0 or c4
== 0) then
608 severity
= (bit32
.extract(VALUE
,15,1) * 4) + (bit32
.extract(VALUE
,23,1) * 2) + (bit32
.extract(VALUE
,30,1) * 1)
609 pushMessage( severity
, messageBuffer
)
613 elseif ( DATA_ID
== 0x5007) then -- PARAMS
614 paramId
= bit32
.extract(VALUE
,24,4)
615 paramValue
= bit32
.extract(VALUE
,0,24)
617 frameType
= paramValue
618 elseif paramId
== 2 then
619 battFailsafeVoltage
= paramValue
620 elseif paramId
== 3 then
621 battFailsafeCapacity
= paramValue
622 elseif paramId
== 4 then
623 battCapacity
= paramValue
629 local function telemetryEnabled()
630 if getValue("RxBt") == 0 then
633 return noTelemetryData
== 0
637 local battSource
= "na"
639 local function calcBattery()
644 cellResult
= getValue("Cels")
646 if type(cellResult
) == "table" then
649 for i
= 1, #cell
do cell
[i
] = 0 end
650 cellsumtype
= #cellResult
651 for i
, v
in pairs(cellResult
) do
652 cellsum
= cellsum
+ v
659 -- cels is not defined let's check if A2 is defined
661 battA2
= getValue("A2")
667 elseif battA2
> 17 then
669 elseif battA2
> 13 then
675 cellmin
= battA2
/cellCount
678 -- A2 is not defined, last chance is battVolt
681 cellsum
= battVolt
*0.1
684 elseif cellsum
> 17 then
686 elseif cellsum
> 13 then
692 cellmin
= cellsum
/cellCount
697 LIPOcelm
= cellmin
*100
698 LIPObatt
= cellsum
*100
701 local function drawBattery()
702 if (battCapacity
> 0) then
703 LIPOperc
= (1 - (battMah
/battCapacity
))*100
707 -- display battery voltage
708 lcd
.drawNumber(maxX
+ 3, 10, LIPObatt
, DBLSIZE
+PREC2
)
710 local xx
= lcd
.getLastRightPos()
711 lcd
.drawText(xx
, 10, "V", 0)
712 lcd
.drawText(xx
, 20, battSource
, SMLSIZE
)
714 -- display lowest cell voltage
715 if LIPOcelm
< 350 then
716 lcd
.drawNumber(maxX
+ 57, 10, LIPOcelm
, DBLSIZE
+BLINK
+PREC2
)
717 lcd
.drawText(lcd
.getLastRightPos(), 10, "Vm", SMLSIZE
+BLINK
)
719 lcd
.drawNumber(maxX
+ 57, 10, LIPOcelm
, DBLSIZE
+PREC2
)
720 lcd
.drawText(lcd
.getLastRightPos(), 10, "Vm", SMLSIZE
)
723 lcd
.drawNumber(maxX
+ 101, 10, battCurrent
, DBLSIZE
+PREC1
)
724 lcd
.drawText(lcd
.getLastRightPos(), 10, "A", SMLSIZE
)
726 local barOffset
= maxX
+ 24
728 lcd
.drawText(barOffset
- 1, 28, "%", SMLSIZE
+RIGHT
)
729 lcd
.drawNumber(lcd
.getLastLeftPos(), 28, LIPOperc
, RIGHT
)
731 -- display capacity bar %
732 lcd
.drawGauge(barOffset
, 28, 55, 7, LIPOperc
, 100)
734 lcd
.drawText(212, 28, "Ah", SMLSIZE
+RIGHT
)
735 lcd
.drawNumber(lcd
.getLastLeftPos(), 28, battCapacity
/100, SMLSIZE
+PREC1
+RIGHT
)
736 lcd
.drawText(lcd
.getLastLeftPos(), 28, "/", SMLSIZE
+RIGHT
)
737 lcd
.drawNumber(lcd
.getLastLeftPos(), 28, battMah
/100, SMLSIZE
+PREC1
+RIGHT
)
739 lcd
.drawPoint(barOffset
+ 13, 28)
740 lcd
.drawPoint(barOffset
+ 13, 34)
742 lcd
.drawPoint(barOffset
+ 27, 28)
743 lcd
.drawPoint(barOffset
+ 27, 34)
745 lcd
.drawPoint(barOffset
+ 41, 28)
746 lcd
.drawPoint(barOffset
+ 41, 34)
749 local function drawFlightMode()
750 lcd
.drawFilledRectangle(0,0, 212, 9, SOLID
)
751 lcd
.drawRectangle(0, 0, 212, 9, SOLID
)
753 if (not telemetryEnabled()) then
754 lcd
.drawFilledRectangle((212-150)/2,18, 150, 30, SOLID
)
755 lcd
.drawText(60, 29, "no telemetry data", INVERS
)
759 local strMode
= flightModes
[frameTypes
[frameType]]
[flightMode
]
761 lcd
.drawText(1, 1, strMode
, SMLSIZE
+INVERS
)
763 if ( simpleMode
== 1) then
764 lcd
.drawText(lcd
.getLastRightPos(), 1, "(S)", SMLSIZE
+INVERS
)
767 if (statusArmed
== 1) then
768 lcd
.drawText(maxX
/2 - 12, 47, "ARMED", SMLSIZE
+INVERS
)
770 lcd
.drawText(maxX
/2 - 18, 47, "DISARMED", SMLSIZE
+INVERS
+BLINK
)
774 local function drawHome()
781 lcd
.drawLine(ax
,ay
,ax
+ alen
,ay
, SOLID
, 0)
783 lcd
.drawLine(ax
+1,ay
-1,ax
+ 2,ay
-2, SOLID
, 0)
784 lcd
.drawLine(ax
+1,ay
+1,ax
+ 2,ay
+2, SOLID
, 0)
786 lcd
.drawLine(ax
+ alen
- 1,ay
-1,ax
+ alen
- 2,ay
-2, SOLID
, 0)
787 lcd
.drawLine(ax
+ alen
- 1,ay
+1,ax
+ alen
- 2,ay
+2, SOLID
, 0)
789 if homeAngle
== -1 then
790 lcd
.drawText(xx
, yy
, "m",SMLSIZE
+RIGHT
+BLINK
)
791 lcd
.drawNumber(lcd
.getLastLeftPos(), yy
, homeDist
, SMLSIZE
+RIGHT
+BLINK
)
792 lcd
.drawNumber(xx
, yy
+ 8, 0, SMLSIZE
+RIGHT
+BLINK
)
794 lcd
.drawText(xx
, yy
, "m",SMLSIZE
+RIGHT
)
795 lcd
.drawNumber(lcd
.getLastLeftPos(), yy
, homeDist
, SMLSIZE
+RIGHT
)
796 lcd
.drawNumber(xx
, yy
+ 8, homeAngle
, SMLSIZE
+RIGHT
)
798 lcd
.drawText(ax
, yy
+ 8, "Angle:",SMLSIZE
)
801 local function drawMessage()
802 lcd
.drawFilledRectangle(0,55, 212, 9, SOLID
)
803 lcd
.drawRectangle(0, 55, 212, 9, SOLID
)
804 local now
= getTime()
805 if (now
- lastMessageTime
) > 300 then
806 lcd
.drawText(1, 56, messageHistory
[messageIdx
-1],SMLSIZE
+INVERS
)
808 lcd
.drawText(1, 56, messageHistory
[messageIdx
-1],SMLSIZE
+INVERS
+BLINK
)
812 local function drawAllMessages()
814 if (messageIdx
<= 6) then
815 for i
= 1, messageIdx
- 1 do
816 lcd
.drawText(1, 1+10*(idx
- 1), messageHistory
[i
],SMLSIZE
)
820 for i
= messageIdx
- 6,messageIdx
- 1 do
821 lcd
.drawText(1, 1+10*(idx
-1), messageHistory
[i
],SMLSIZE
)
827 local function drawGPSStatus()
830 lcd
.drawRectangle(xx
,yy
,50,18,SOLID
)
833 local strStatus
= gpsStatuses
[gpsStatus
]
836 if gpsStatus
> 2 then
837 lcd
.drawFilledRectangle(xx
,yy
,50,18,SOLID
)
838 if homeAngle
~= -1 then
841 lcd
.drawText(xx
+2, yy
+2, strStatus
, SMLSIZE
+INVERS
)
842 lcd
.drawNumber(212, yy
+2, numSats
, SMLSIZE
+INVERS
+RIGHT
)
843 lcd
.drawText(xx
+2, yy
+10, "Hdop ", SMLSIZE
+INVERS
)
845 if gpsHdopC
> 100 then
846 lcd
.drawNumber(212, yy
+10, gpsHdopC
, SMLSIZE
+INVERS
+RIGHT
+PREC1
+flags
)
848 lcd
.drawNumber(212, yy
+10, gpsHdopC
, SMLSIZE
+INVERS
+RIGHT
+PREC1
+flags
)
850 lcd
.drawText(maxX
+ 30, 40, "AltAsl", SMLSIZE
+RIGHT
)
851 lcd
.drawText(maxX
+ 30, 47, "m", SMLSIZE
+RIGHT
)
852 lcd
.drawNumber(lcd
.getLastLeftPos(), 47, gpsAlt
/10, SMLSIZE
+RIGHT
)
854 lcd
.drawText(xx
+5, yy
+5, strStatus
, INVERS
+BLINK
)
855 lcd
.drawText(maxX
+ 30, 40, "AltAsl", SMLSIZE
+RIGHT
)
856 lcd
.drawText(maxX
+ 30, 47, "m", SMLSIZE
+RIGHT
+BLINK
)
857 lcd
.drawNumber(lcd
.getLastLeftPos(), 47, 0, SMLSIZE
+RIGHT
+BLINK
)
861 local function drawGrid()
862 lcd
.drawLine(maxX
, 0, maxX
, 63, SOLID
, 0)
863 lcd
.drawRectangle(maxX
,38,31,18,SOLID
)
866 local timerRunning
= 0
868 local function checkLandingStatus()
869 if ( timerRunning
== 0 and landComplete
== 1 and lastTimerStart
== 0) then
872 if (timerRunning
== 1 and landComplete
== 0 and lastTimerStart
~= 0) then
876 timerRunning
= landComplete
880 local function calcFlightTime()
882 if ( lastTimerStart
~= 0) then
883 elapsed
= getTime()/100 - lastTimerStart
885 flightTime
= elapsed
+ seconds
888 -- draws a line centered at ox,oy with given angle and length W/O CROPPING
889 local function drawLine(ox
,oy
,angle
,len
,style
,maxX
,maxY
)
890 local xx
= math
.cos(math
.rad(angle
)) * len
* 0.5
891 local yy
= math
.sin(math
.rad(angle
)) * len
* 0.5
898 lcd
.drawLine(x1
,y1
,x2
,y2
, style
,0)
901 -- draws a line centered at ox,oy with given angle and length WITH CROPPING
902 local function drawCroppedLine(ox
,oy
,angle
,len
,style
,maxX
,maxY
)
904 local xx
= math
.cos(math
.rad(angle
)) * len
* 0.5
905 local yy
= math
.sin(math
.rad(angle
)) * len
* 0.5
912 if (x1
>= maxX
and x2
>= maxX
) then
916 y1
= y1
- math
.tan(math
.rad(angle
)) * (maxX
- x1
)
920 y2
= y2
+ math
.tan(math
.rad(angle
)) * (maxX
- x2
)
923 lcd
.drawLine(x1
,y1
,x2
,y2
, style
,0)
926 local function drawFailsafe()
927 if ekfFailsafe
> 0 then
928 if lastEkfFailsafe
== 0 then
931 lcd
.drawText(maxX
/2 - 28, 47, "EKF FAILSAFE", SMLSIZE
+INVERS
+BLINK
)
933 if batteryFailsafe
> 0 then
934 if lastBatteryFailsafe
== 0 then
937 lcd
.drawText(maxX
/2 - 30, 47, "BATT FAILSAFE", SMLSIZE
+INVERS
+BLINK
)
939 lastEkfFailsafe
= ekfFailsafe
940 lastBatteryFailsafe
= batteryFailsafe
943 local function drawPitch()
946 -- horizon min max +/- 30°
952 if (pitch
< -30) then
956 -- y normalized at 32 +/-20 (0.75 = 20/32)
958 -- horizon, lower half of HUD filled in grey
959 --lcd.drawFilledRectangle(minX,y,maxX-minX,maxY-y + 1,GREY_DEFAULT)
961 -- center indicators for vSpeed and alt
963 lcd
.drawLine(minX
,32 - 5,minX
+ width
,32 - 5, SOLID
, 0)
964 lcd
.drawLine(minX
,32 + 4,minX
+ width
,32 + 4, SOLID
, 0)
965 lcd
.drawLine(minX
+ width
+ 1,32 + 4,minX
+ width
+ 5,32, SOLID
, 0)
966 lcd
.drawLine(minX
+ width
+ 1,32 - 4,minX
+ width
+ 5,32, SOLID
, 0)
967 lcd
.drawPoint(minX
+ width
+ 5,32)
969 lcd
.drawLine(maxX
- width
- 1,32 - 5,maxX
- 1,32 - 5,SOLID
,0)
970 lcd
.drawLine(maxX
- width
- 1,32 + 4,maxX
- 1,32 + 4,SOLID
,0)
971 lcd
.drawLine(maxX
- width
- 2,32 + 4,maxX
- width
- 6,32, SOLID
, 0)
972 lcd
.drawLine(maxX
- width
- 2,32 - 4,maxX
- width
- 6,32, SOLID
, 0)
973 lcd
.drawPoint(maxX
- width
- 6,32)
975 local xx
= maxX
- width
- 2
977 if homeAlt
< 10 then -- 2 digits with decimal
978 lcd
.drawNumber(maxX
,32 - 3,homeAlt
* 10,SMLSIZE
+PREC1
+RIGHT
)
980 lcd
.drawNumber(maxX
,32 - 3,homeAlt
,SMLSIZE
+RIGHT
)
983 if homeAlt
> -10 then -- 1 digit with sign
984 lcd
.drawNumber(maxX
,32 - 3,homeAlt
* 10,SMLSIZE
+PREC1
+RIGHT
)
985 else -- 3 digits with sign
986 lcd
.drawNumber(maxX
,32 - 3,homeAlt
,SMLSIZE
+RIGHT
)
990 if (vSpeed
> 999) then
991 lcd
.drawNumber(minX
+ 1,32 - 3,vSpeed
*0.1,SMLSIZE
)
992 elseif (vSpeed
< -99) then
993 lcd
.drawNumber(minX
+ 1,32 - 3,vSpeed
* 0.1,SMLSIZE
)
995 lcd
.drawNumber(minX
+ 1,32 - 3,vSpeed
,SMLSIZE
+PREC1
)
997 -- up pointing center arrow
998 local x
= math
.floor(maxX
/2)
999 lcd
.drawLine(x
-10,34 + 5,x
,34 ,SOLID
,0)
1000 lcd
.drawLine(x
+1 ,34 ,x
+ 10, 34 + 5,SOLID
,0)
1003 local function drawRoll()
1005 local r2
= 10 --vertical distance between roll horiz segments
1006 local cx
,cy
,dx
,dy
,ccx
,ccy
,cccx
,cccy
1007 -- no roll ==> segments are vertical, offsets are multiples of r2
1008 if ( roll
== 0) then
1018 -- center line offsets
1019 dx
= math
.cos(math
.rad(90 - r
)) * -pitch
1020 dy
= math
.sin(math
.rad(90 - r
)) * pitch
1022 cx
= math
.cos(math
.rad(90 - r
)) * r2
1023 cy
= math
.sin(math
.rad(90 - r
)) * r2
1025 ccx
= math
.cos(math
.rad(90 - r
)) * 2 * r2
1026 ccy
= math
.sin(math
.rad(90 - r
)) * 2 * r2
1028 cccx
= math
.cos(math
.rad(90 - r
)) * 3 * r2
1029 cccy
= math
.sin(math
.rad(90 - r
)) * 3 * r2
1031 local x
= math
.floor(maxX
/2)
1032 drawCroppedLine(dx
+ x
- cccx
,dy
+ 32 + cccy
,r
,5,DOTTED
,maxX
,maxY
)
1033 drawCroppedLine(dx
+ x
- ccx
,dy
+ 32 + ccy
,r
,7,DOTTED
,maxX
,maxY
)
1034 drawCroppedLine(dx
+ x
- cx
,dy
+ 32 + cy
,r
,10,DOTTED
,maxX
,maxY
)
1035 drawCroppedLine(dx
+ x
,dy
+ 32,r
,28,SOLID
,maxX
,maxY
)
1036 drawCroppedLine(dx
+ x
+ cx
,dy
+ 32 - cy
,r
,10,DOTTED
,maxX
,maxY
)
1037 drawCroppedLine(dx
+ x
+ ccx
,dy
+ 32 - ccy
,r
,7,DOTTED
,maxX
,maxY
)
1038 drawCroppedLine(dx
+ x
+ cccx
,dy
+ 32 - cccy
,r
,5,DOTTED
,maxX
,maxY
)
1041 local function roundTo(val
,int
)
1042 return math
.floor(val
/int
) * int
1045 local function drawYaw()
1046 local northX
= math
.floor(maxX
/2) - 2
1047 local offset
= northX
- 4
1048 local yawRounded
= math
.floor(yaw
)
1049 local yawWindow
= roundTo(yaw
,10)
1050 local maxXHalf
= math
.floor(maxX
/2)
1051 local yawWindowOn
= false
1052 local flags
= SMLSIZE
1053 if (not(yawWindow
== 0 or yawWindow
== 90 or yawWindow
== 180 or yawWindow
== 270 or yawWindow
== 360)) then
1057 if (yawRounded
== 0 or yawRounded
== 360) then
1058 lcd
.drawText(northX
- offset
, minY
+1, "W", SMLSIZE
)
1059 lcd
.drawText(northX
, minY
+1, "N", flags
)
1060 lcd
.drawText(northX
+ offset
, minY
+1, "E", SMLSIZE
)
1061 elseif (yawRounded
== 90) then
1062 lcd
.drawText(northX
- offset
, minY
+1, "N", SMLSIZE
)
1063 lcd
.drawText(northX
, minY
+1, "E", flags
)
1064 lcd
.drawText(northX
+ offset
, minY
+1, "S", SMLSIZE
)
1065 elseif (yawRounded
== 180) then
1066 lcd
.drawText(northX
- offset
, minY
+1, "W", SMLSIZE
)
1067 lcd
.drawText(northX
, minY
+1, "S", flags
)
1068 lcd
.drawText(northX
+ offset
, minY
+1, "E", SMLSIZE
)
1069 elseif (yawRounded
== 270) then
1070 lcd
.drawText(northX
- offset
, minY
+1, "S", SMLSIZE
)
1071 lcd
.drawText(northX
, minY
+1, "W", flags
)
1072 lcd
.drawText(northX
+ offset
, minY
+1, "N", SMLSIZE
)
1073 elseif ( yaw
> 0 and yaw
< 90) then
1074 northX
= (maxXHalf
- 2) - 0.3*yaw
1075 lcd
.drawText(northX
, minY
+1, "N", flags
)
1076 lcd
.drawText(northX
+ offset
, minY
+1, "E", SMLSIZE
)
1078 lcd
.drawText(northX
+ offset
+ offset
, minY
+1, "S", SMLSIZE
)
1080 elseif ( yaw
> 90 and yaw
< 180) then
1081 northX
= (maxXHalf
- 2) - 0.3*(yaw
- 180)
1082 lcd
.drawText(northX
- offset
, minY
+1, "E", SMLSIZE
)
1083 lcd
.drawText(northX
, minY
+1, "S", flags
)
1085 lcd
.drawText(northX
+ offset
, minY
+1, "W", SMLSIZE
)
1087 elseif ( yaw
> 180 and yaw
< 270) then
1088 northX
= (maxXHalf
- 2) - 0.3*(yaw
- 270)
1089 lcd
.drawText(northX
, minY
+1, "W", SMLSIZE
)
1090 lcd
.drawText(northX
- offset
, minY
+1, "S", flags
)
1092 lcd
.drawText(northX
- offset
- offset
, minY
+1, "E", SMLSIZE
)
1094 elseif ( yaw
> 270 and yaw
< 360) then
1095 northX
= (maxXHalf
- 2) - 0.3*(yaw
- 360)
1096 lcd
.drawText(northX
, minY
+1, "N", SMLSIZE
)
1097 lcd
.drawText(northX
- offset
, minY
+1, "W", flags
)
1099 lcd
.drawText(northX
- offset
- offset
, minY
+1, "S", SMLSIZE
)
1102 lcd
.drawText(northX
+ offset
, minY
+1, "E", SMLSIZE
)
1105 lcd
.drawLine(minX
, minY
+7, maxX
, minY
+7, SOLID
, 0)
1110 elseif (yaw
< 100) then
1115 lcd
.drawNumber(minX
+ offset
+ xx
, minY
, yaw
, MIDSIZE
+INVERS
)
1118 local function drawHud()
1124 local function drawHomeDirection()
1127 local angle
= math
.floor(yaw
- homeAngle
)
1128 if ( math
.abs(angle
) > 45 and math
.abs(angle
) < 315) then
1133 local x1
= ox
+ r1
* math
.cos(math
.rad(angle
- 90))
1134 local y1
= oy
+ r1
* math
.sin(math
.rad(angle
- 90))
1135 local x2
= ox
+ r2
* math
.cos(math
.rad(angle
- 90 + 120))
1136 local y2
= oy
+ r2
* math
.sin(math
.rad(angle
- 90 + 120))
1137 local x3
= ox
+ r2
* math
.cos(math
.rad(angle
- 90 - 120))
1138 local y3
= oy
+ r2
* math
.sin(math
.rad(angle
- 90 - 120))
1140 lcd
.drawLine(x1
,y1
,x2
,y2
,SOLID
,1)
1141 lcd
.drawLine(x1
,y1
,x3
,y3
,SOLID
,1)
1142 lcd
.drawLine(ox
,oy
,x2
,y2
,SOLID
,1)
1143 lcd
.drawLine(ox
,oy
,x3
,y3
,SOLID
,1)
1146 local function drawFlightTime()
1147 lcd
.drawText(maxX
+ 1, 1, "T:", SMLSIZE
+INVERS
)
1148 lcd
.drawTimer(lcd
.getLastRightPos()+1, 1, flightTime
, SMLSIZE
+INVERS
)
1151 local function drawRSSI()
1152 local rssi
= getRSSI()
1153 lcd
.drawText(212, 1, rssi
, SMLSIZE
+INVERS
+RIGHT
)
1154 lcd
.drawText(lcd
.getLastLeftPos(), 1, "Rssi:", SMLSIZE
+INVERS
+RIGHT
)
1157 local function drawTxVoltage()
1158 txVId
=getFieldInfo("tx-voltage").id
1159 txV
= getValue(txVId
)*10
1161 lcd
.drawText(150, 1, "Tx:", SMLSIZE
+INVERS
)
1162 lcd
.drawNumber(lcd
.getLastRightPos(), 1, txV
, SMLSIZE
+INVERS
+PREC1
)
1163 lcd
.drawText(lcd
.getLastRightPos(), 1, "v", SMLSIZE
+INVERS
)
1166 local function drawCircle(x0
,y0
,radius
)
1171 local err
= dx
- bit32
.lshift(radius
,1)--(radius << 1)
1174 lcd
.drawPoint(x0
+ x
, y0
+ y
);
1175 lcd
.drawPoint(x0
+ y
, y0
+ x
);
1176 lcd
.drawPoint(x0
- y
, y0
+ x
);
1177 lcd
.drawPoint(x0
- x
, y0
+ y
);
1178 lcd
.drawPoint(x0
- x
, y0
- y
);
1179 lcd
.drawPoint(x0
- y
, y0
- x
);
1180 lcd
.drawPoint(x0
+ y
, y0
- x
);
1181 lcd
.drawPoint(x0
+ x
, y0
- y
);
1192 err
= err
+ dx
- bit32
.lshift(radius
,1)--(radius << 1);
1198 local lastStatusArmed
= 0
1199 local lastGpsStatus
= 0
1200 local lastFlightMode
= 0
1201 local lastBattLevel
= 0
1203 local batLevels
= {}
1218 local function checkSoundEvents()
1219 if (battCapacity
> 0) then
1220 batLevel
= (1 - (battMah
/battCapacity
))*100
1225 if batLevel
< (batLevels
[lastBattLevel
] + 1) and lastBattLevel
<= 11 then
1226 playSound("bat"..batLevels
[lastBattLevel
])
1227 lastBattLevel
= lastBattLevel
+ 1
1230 if statusArmed
== 1 and lastStatusArmed
== 0 then
1231 lastStatusArmed
= statusArmed
1233 elseif statusArmed
== 0 and lastStatusArmed
== 1 then
1234 lastStatusArmed
= statusArmed
1235 playSound("disarmed")
1238 if gpsStatus
> 2 and lastGpsStatus
<= 2 then
1239 lastGpsStatus
= gpsStatus
1241 elseif gpsStatus
<= 2 and lastGpsStatus
> 2 then
1242 lastGpsStatus
= gpsStatus
1243 playSound("gpsnofix")
1246 if flightMode
~= lastFlightMode
then
1247 lastFlightMode
= flightMode
1248 playSoundByFrameTypeAndFlightMode(frameType
,flightMode
)
1251 --------------------------------------------------------------------------------
1253 --------------------------------------------------------------------------------
1254 local showMessages
= false
1256 local function background()
1262 local function symMode()
1271 local function run(event
)
1273 if event
== EVT_PLUS_FIRST
or event
== EVT_MINUS_FIRST
then
1274 showMessages
= not showMessages
1277 if (clock % 8 == 0) then
1284 if showMessages
then
1287 --drawCircle(100,32,30)
1298 checkLandingStatus()
1312 local function init()
1313 pushMessage(6,"Yaapu X9D+ telemetry script v1.1")
1317 --------------------------------------------------------------------------------
1319 --------------------------------------------------------------------------------
1320 return {run
=run
, background
=background
, init
=init
}