5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
26 #include "telemetry/frsky.h"
27 #include "telemetry/multi.h"
30 #include "lua/lua_exports_x12s.inc" // this line must be after lua headers
31 #elif defined(RADIO_T16)
32 #include "lua/lua_exports_t16.inc"
34 #include "lua/lua_exports_x10.inc"
36 #include "lua/lua_exports_x9e.inc"
37 #elif defined(RADIO_X7)
38 #include "lua/lua_exports_x7.inc"
39 #elif defined(RADIO_T12)
40 #include "lua/lua_exports_t12.inc"
41 #elif defined(PCBX9LITES)
42 #include "lua/lua_exports_x9lites.inc"
43 #elif defined(PCBX9LITE)
44 #include "lua/lua_exports_x9lite.inc"
45 #elif defined(PCBXLITES)
46 #include "lua/lua_exports_xlites.inc"
47 #elif defined(PCBXLITE)
48 #include "lua/lua_exports_xlite.inc"
49 #elif defined(PCBTARANIS)
50 #include "lua/lua_exports_x9d.inc"
54 #define RADIO_VERSION FLAVOUR "-simu"
56 #define RADIO_VERSION FLAVOUR
59 #define FIND_FIELD_DESC 0x01
61 #define KEY_EVENTS(xxx, yyy) \
62 { "EVT_"#xxx"_FIRST", EVT_KEY_FIRST(yyy) }, \
63 { "EVT_"#xxx"_BREAK", EVT_KEY_BREAK(yyy) }, \
64 { "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \
65 { "EVT_"#xxx"_REPT", EVT_KEY_REPT(yyy) }
68 @function getVersion()
72 @retval string OpenTX version (ie "2.1.5")
74 @retval multiple (available since 2.1.7) returns 5 values:
75 * (string) OpenTX version (ie "2.1.5")
76 * (string) radio type: `x12s`, `x10`, `x9e`, `x9d+`, `x9d` or `x7`.
77 If running in simulator the "-simu" is added
78 * (number) major version (ie 2 if version 2.1.5)
79 * (number) minor version (ie 1 if version 2.1.5)
80 * (number) revision number (ie 5 if version 2.1.5)
82 @status current Introduced in 2.0.0, expanded in 2.1.7, radio type strings changed in 2.2.0
86 This example also runs in OpenTX versions where the function returned only one value:
89 local function run(event)
90 local ver, radio, maj, minor, rev = getVersion()
91 print("version: "..ver)
92 if radio then print ("radio: "..radio) end
93 if maj then print ("maj: "..maj) end
94 if minor then print ("minor: "..minor) end
95 if rev then print ("rev: "..rev) end
101 Output of the above script in simulator:
110 static int luaGetVersion(lua_State
* L
)
112 lua_pushstring(L
, VERSION
);
113 lua_pushstring(L
, RADIO_VERSION
);
114 lua_pushnumber(L
, VERSION_MAJOR
);
115 lua_pushnumber(L
, VERSION_MINOR
);
116 lua_pushnumber(L
, VERSION_REVISION
);
123 Return the time since the radio was started in multiple of 10ms
125 @retval number Number of 10ms ticks since the radio was started Example:
126 run time: 12.54 seconds, return value: 1254
128 The timer internally uses a 32-bit counter which is enough for 497 days so
129 overflows will not happen.
131 @status current Introduced in 2.0.0
133 static int luaGetTime(lua_State
* L
)
135 lua_pushunsigned(L
, get_tmr10ms());
139 static void luaPushDateTime(lua_State
* L
, uint32_t year
, uint32_t mon
, uint32_t day
,
140 uint32_t hour
, uint32_t min
, uint32_t sec
)
142 uint32_t hour12
= hour
;
147 else if (hour
> 12) {
150 lua_createtable(L
, 0, 8);
151 lua_pushtableinteger(L
, "year", year
);
152 lua_pushtableinteger(L
, "mon", mon
);
153 lua_pushtableinteger(L
, "day", day
);
154 lua_pushtableinteger(L
, "hour", hour
);
155 lua_pushtableinteger(L
, "min", min
);
156 lua_pushtableinteger(L
, "sec", sec
);
157 lua_pushtableinteger(L
, "hour12", hour12
);
159 lua_pushtablestring(L
, "suffix", "am");
162 lua_pushtablestring(L
, "suffix", "pm");
167 @function getDateTime()
169 Return current system date and time that is kept by the RTC unit
171 @retval table current date and time, table elements:
172 * `year` (number) year
173 * `mon` (number) month
174 * `day` (number) day of month
175 * `hour` (number) hours
176 * `hour12` (number) hours in US format
177 * `min` (number) minutes
178 * `sec` (number) seconds
179 * `suffix` (text) am or pm
181 static int luaGetDateTime(lua_State
* L
)
185 luaPushDateTime(L
, utm
.tm_year
+ TM_YEAR_BASE
, utm
.tm_mon
+ 1, utm
.tm_mday
, utm
.tm_hour
, utm
.tm_min
, utm
.tm_sec
);
190 @function getRtcTime()
192 Return current RTC system date as unix timstamp (in seconds since 1. Jan 1970)
194 Please note the RTC timestamp is kept internally as a 32bit integer, which will overflow
197 @retval number Number of seconds elapsed since 1. Jan 1970
201 static int luaGetRtcTime(lua_State
* L
)
203 lua_pushunsigned(L
, g_rtcTime
);
208 static void luaPushLatLon(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
209 /* result is lua table containing members ["lat"] and ["lon"] as lua_Number (doubles) in decimal degrees */
211 lua_createtable(L
, 0, 5);
212 lua_pushtablenumber(L
, "lat", telemetryItem
.gps
.latitude
* 0.000001); // floating point multiplication is faster than division
213 lua_pushtablenumber(L
, "pilot-lat", telemetryItem
.pilotLatitude
* 0.000001);
214 lua_pushtablenumber(L
, "lon", telemetryItem
.gps
.longitude
* 0.000001);
215 lua_pushtablenumber(L
, "pilot-lon", telemetryItem
.pilotLongitude
* 0.000001);
217 int8_t delay
= telemetryItem
.getDelaySinceLastValue();
219 lua_pushtableinteger(L
, "delay", delay
);
221 lua_pushtablenil(L
, "delay");
224 static void luaPushTelemetryDateTime(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
226 luaPushDateTime(L
, telemetryItem
.datetime
.year
, telemetryItem
.datetime
.month
, telemetryItem
.datetime
.day
,
227 telemetryItem
.datetime
.hour
, telemetryItem
.datetime
.min
, telemetryItem
.datetime
.sec
);
230 static void luaPushCells(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
232 if (telemetryItem
.cells
.count
== 0)
233 lua_pushinteger(L
, (int)0); // returns zero if no cells
235 lua_createtable(L
, telemetryItem
.cells
.count
, 0);
236 for (int i
= 0; i
< telemetryItem
.cells
.count
; i
++) {
237 lua_pushnumber(L
, i
+ 1);
238 lua_pushnumber(L
, telemetryItem
.cells
.values
[i
].value
* 0.01f
);
244 void luaGetValueAndPush(lua_State
* L
, int src
)
246 getvalue_t value
= getValue(src
); // ignored for GPS, DATETIME, and CELLS
248 if (src
>= MIXSRC_FIRST_TELEM
&& src
<= MIXSRC_LAST_TELEM
) {
249 div_t qr
= div(src
-MIXSRC_FIRST_TELEM
, 3);
251 if (TELEMETRY_STREAMING() && telemetryItems
[qr
.quot
].isAvailable()) {
252 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[qr
.quot
];
253 switch (telemetrySensor
.unit
) {
255 luaPushLatLon(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
258 luaPushTelemetryDateTime(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
261 lua_pushstring(L
, telemetryItems
[qr
.quot
].text
);
265 luaPushCells(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
268 // deliberate no break here to properly return `Cels-` and `Cels+`
270 if (telemetrySensor
.prec
> 0)
271 lua_pushnumber(L
, float(value
)/telemetrySensor
.getPrecDivisor());
273 lua_pushinteger(L
, value
);
278 // telemetry not working, return zero for telemetry sources
279 lua_pushinteger(L
, (int)0);
282 else if (src
== MIXSRC_TX_VOLTAGE
) {
283 lua_pushnumber(L
, float(value
) * 0.1f
);
286 lua_pushinteger(L
, value
);
291 Return field data for a given field name
293 bool luaFindFieldByName(const char * name
, LuaField
& field
, unsigned int flags
)
295 // TODO better search method (binary lookup)
296 for (unsigned int n
=0; n
<DIM(luaSingleFields
); ++n
) {
297 if (!strcmp(name
, luaSingleFields
[n
].name
)) {
298 field
.id
= luaSingleFields
[n
].id
;
299 if (flags
& FIND_FIELD_DESC
) {
300 strncpy(field
.desc
, luaSingleFields
[n
].desc
, sizeof(field
.desc
)-1);
301 field
.desc
[sizeof(field
.desc
)-1] = '\0';
304 field
.desc
[0] = '\0';
310 // search in multiples
311 unsigned int len
= strlen(name
);
312 for (unsigned int n
=0; n
<DIM(luaMultipleFields
); ++n
) {
313 const char * fieldName
= luaMultipleFields
[n
].name
;
314 unsigned int fieldLen
= strlen(fieldName
);
315 if (!strncmp(name
, fieldName
, fieldLen
)) {
317 if (len
== fieldLen
+1 && isdigit(name
[fieldLen
])) {
318 index
= name
[fieldLen
] - '1';
320 else if (len
== fieldLen
+2 && isdigit(name
[fieldLen
]) && isdigit(name
[fieldLen
+1])) {
321 index
= 10 * (name
[fieldLen
] - '0') + (name
[fieldLen
+1] - '1');
326 if (index
< luaMultipleFields
[n
].count
) {
327 if(luaMultipleFields
[n
].id
== MIXSRC_FIRST_TELEM
)
328 field
.id
= luaMultipleFields
[n
].id
+ index
*3;
330 field
.id
= luaMultipleFields
[n
].id
+ index
;
331 if (flags
& FIND_FIELD_DESC
) {
332 snprintf(field
.desc
, sizeof(field
.desc
)-1, luaMultipleFields
[n
].desc
, index
+1);
333 field
.desc
[sizeof(field
.desc
)-1] = '\0';
336 field
.desc
[0] = '\0';
343 // search in telemetry
344 field
.desc
[0] = '\0';
345 for (int i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
346 if (isTelemetryFieldAvailable(i
)) {
347 char sensorName
[TELEM_LABEL_LEN
+1];
348 int len
= zchar2str(sensorName
, g_model
.telemetrySensors
[i
].label
, TELEM_LABEL_LEN
);
349 if (!strncmp(sensorName
, name
, len
)) {
350 if (name
[len
] == '\0') {
351 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
;
352 field
.desc
[0] = '\0';
355 else if (name
[len
] == '-' && name
[len
+1] == '\0') {
356 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
+ 1;
357 field
.desc
[0] = '\0';
360 else if (name
[len
] == '+' && name
[len
+1] == '\0') {
361 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
+ 2;
362 field
.desc
[0] = '\0';
369 return false; // not found
373 @function sportTelemetryPop()
375 Pops a received SPORT packet from the queue. Please note that only packets using a data ID within 0x5000 to 0x50FF
376 (frame ID == 0x10), as well as packets with a frame ID equal 0x32 (regardless of the data ID) will be passed to
377 the LUA telemetry receive queue.
379 @retval nil queue does not contain any (or enough) bytes to form a whole packet
381 @retval multiple returns 4 values:
387 @status current Introduced in 2.2.0
389 static int luaSportTelemetryPop(lua_State
* L
)
391 if (!luaInputTelemetryFifo
) {
392 luaInputTelemetryFifo
= new Fifo
<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE
>();
393 if (!luaInputTelemetryFifo
) {
398 if (luaInputTelemetryFifo
->size() >= sizeof(SportTelemetryPacket
)) {
399 SportTelemetryPacket packet
;
400 for (uint8_t i
=0; i
<sizeof(packet
); i
++) {
401 luaInputTelemetryFifo
->pop(packet
.raw
[i
]);
403 lua_pushnumber(L
, packet
.physicalId
);
404 lua_pushnumber(L
, packet
.primId
);
405 lua_pushnumber(L
, packet
.dataId
);
406 lua_pushunsigned(L
, packet
.value
);
413 #define BIT(x, index) (((x) >> index) & 0x01)
414 uint8_t getDataId(uint8_t physicalId
)
416 uint8_t result
= physicalId
;
417 result
+= (BIT(physicalId
, 0) ^ BIT(physicalId
, 1) ^ BIT(physicalId
, 2)) << 5;
418 result
+= (BIT(physicalId
, 2) ^ BIT(physicalId
, 3) ^ BIT(physicalId
, 4)) << 6;
419 result
+= (BIT(physicalId
, 0) ^ BIT(physicalId
, 2) ^ BIT(physicalId
, 4)) << 7;
424 @function sportTelemetryPush()
426 This functions allows for sending SPORT telemetry data toward the receiver,
427 and more generally, to anything connected SPORT bus on the receiver or transmitter.
429 When called without parameters, it will only return the status of the output buffer without sending anything.
431 @param sensorId physical sensor ID
433 @param frameId frame ID
435 @param dataId data ID
439 @retval boolean data queued in output buffer or not.
441 @status current Introduced in 2.2.0
444 static int luaSportTelemetryPush(lua_State
* L
)
446 if (!IS_FRSKY_SPORT_PROTOCOL()) {
447 lua_pushboolean(L
, false);
451 if (lua_gettop(L
) == 0) {
452 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
456 uint16_t dataId
= luaL_checkunsigned(L
, 3);
458 if (outputTelemetryBuffer
.isAvailable()) {
459 for (uint8_t i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
460 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[i
];
461 if (sensor
.id
== dataId
) {
462 if (sensor
.frskyInstance
.rxIndex
== TELEMETRY_ENDPOINT_SPORT
) {
463 SportTelemetryPacket packet
;
464 packet
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
465 packet
.primId
= luaL_checkunsigned(L
, 2);
466 packet
.dataId
= dataId
;
467 packet
.value
= luaL_checkunsigned(L
, 4);
468 outputTelemetryBuffer
.pushSportPacketWithBytestuffing(packet
);
471 outputTelemetryBuffer
.sport
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
472 outputTelemetryBuffer
.sport
.primId
= luaL_checkunsigned(L
, 2);
473 outputTelemetryBuffer
.sport
.dataId
= dataId
;
474 outputTelemetryBuffer
.sport
.value
= luaL_checkunsigned(L
, 4);
476 outputTelemetryBuffer
.setDestination(sensor
.frskyInstance
.rxIndex
);
477 lua_pushboolean(L
, true);
482 // sensor not found, we send the frame to the SPORT line
484 SportTelemetryPacket packet
;
485 packet
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
486 packet
.primId
= luaL_checkunsigned(L
, 2);
487 packet
.dataId
= dataId
;
488 packet
.value
= luaL_checkunsigned(L
, 4);
489 outputTelemetryBuffer
.pushSportPacketWithBytestuffing(packet
);
491 uint8_t destination
= (IS_INTERNAL_MODULE_ON() ? INTERNAL_MODULE
: EXTERNAL_MODULE
);
492 outputTelemetryBuffer
.setDestination(isModulePXX2(destination
) ? (destination
<< 2) : TELEMETRY_ENDPOINT_SPORT
);
494 outputTelemetryBuffer
.setDestination(TELEMETRY_ENDPOINT_SPORT
);
496 lua_pushboolean(L
, true);
501 lua_pushboolean(L
, false);
507 @function accessTelemetryPush()
509 This functions allows for sending SPORT / ACCESS telemetry data toward the receiver,
510 and more generally, to anything connected SPORT bus on the receiver or transmitter.
512 When called without parameters, it will only return the status of the output buffer without sending anything.
514 @param module module index (0 = internal, 1 = external)
516 @param rxUid receiver index
518 @param sensorId physical sensor ID
520 @param frameId frame ID
522 @param dataId data ID
526 @retval boolean data queued in output buffer or not.
528 @status current Introduced in 2.3
532 bool getDefaultAccessDestination(uint8_t & destination
)
534 for (uint8_t i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
535 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[i
];
536 if (sensor
.type
== TELEM_TYPE_CUSTOM
) {
537 TelemetryItem sensorItem
= telemetryItems
[i
];
538 if (sensorItem
.isFresh()) {
539 destination
= sensor
.frskyInstance
.rxIndex
;
547 static int luaAccessTelemetryPush(lua_State
* L
)
549 if (lua_gettop(L
) == 0) {
550 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
554 if (outputTelemetryBuffer
.isAvailable()) {
555 int8_t module
= luaL_checkinteger(L
, 1);
556 uint8_t rxUid
= luaL_checkunsigned(L
, 2);
560 if (!getDefaultAccessDestination(destination
)) {
561 lua_pushboolean(L
, false);
566 destination
= (module
<< 2) + rxUid
;
569 outputTelemetryBuffer
.sport
.physicalId
= getDataId(luaL_checkunsigned(L
, 3));
570 outputTelemetryBuffer
.sport
.primId
= luaL_checkunsigned(L
, 4);
571 outputTelemetryBuffer
.sport
.dataId
= luaL_checkunsigned(L
, 5);
572 outputTelemetryBuffer
.sport
.value
= luaL_checkunsigned(L
, 6);
573 outputTelemetryBuffer
.setDestination(destination
);
574 lua_pushboolean(L
, true);
578 lua_pushboolean(L
, false);
583 #if defined(CROSSFIRE)
585 @function crossfireTelemetryPop()
587 Pops a received Crossfire Telemetry packet from the queue.
589 @retval nil queue does not contain any (or enough) bytes to form a whole packet
591 @retval multiple returns 2 values:
593 * packet (table) data bytes
595 @status current Introduced in 2.2.0
597 static int luaCrossfireTelemetryPop(lua_State
* L
)
599 if (!luaInputTelemetryFifo
) {
600 luaInputTelemetryFifo
= new Fifo
<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE
>();
601 if (!luaInputTelemetryFifo
) {
606 uint8_t length
= 0, data
= 0;
607 if (luaInputTelemetryFifo
->probe(length
) && luaInputTelemetryFifo
->size() >= uint32_t(length
)) {
608 // length value includes the length field
609 luaInputTelemetryFifo
->pop(length
);
610 luaInputTelemetryFifo
->pop(data
); // command
611 lua_pushnumber(L
, data
);
613 for (uint8_t i
=1; i
<length
-1; i
++) {
614 luaInputTelemetryFifo
->pop(data
);
615 lua_pushinteger(L
, i
);
616 lua_pushinteger(L
, data
);
626 @function crossfireTelemetryPush()
628 This functions allows for sending telemetry data toward the TBS Crossfire link.
630 When called without parameters, it will only return the status of the output buffer without sending anything.
632 @param command command
634 @param data table of data bytes
636 @retval boolean data queued in output buffer or not.
638 @status current Introduced in 2.2.0
640 static int luaCrossfireTelemetryPush(lua_State
* L
)
642 if (telemetryProtocol
!= PROTOCOL_TELEMETRY_CROSSFIRE
) {
643 lua_pushboolean(L
, false);
647 if (lua_gettop(L
) == 0) {
648 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
650 else if (outputTelemetryBuffer
.isAvailable()) {
651 uint8_t command
= luaL_checkunsigned(L
, 1);
652 luaL_checktype(L
, 2, LUA_TTABLE
);
653 uint8_t length
= luaL_len(L
, 2);
654 outputTelemetryBuffer
.pushByte(MODULE_ADDRESS
);
655 outputTelemetryBuffer
.pushByte(2 + length
); // 1(COMMAND) + data length + 1(CRC)
656 outputTelemetryBuffer
.pushByte(command
); // COMMAND
657 for (int i
=0; i
<length
; i
++) {
658 lua_rawgeti(L
, 2, i
+1);
659 outputTelemetryBuffer
.pushByte(luaL_checkunsigned(L
, -1));
661 outputTelemetryBuffer
.pushByte(crc8(outputTelemetryBuffer
.data
+2, 1 + length
));
662 outputTelemetryBuffer
.setDestination(TELEMETRY_ENDPOINT_SPORT
);
663 lua_pushboolean(L
, true);
666 lua_pushboolean(L
, false);
673 @function getFieldInfo(name)
675 Return detailed information about field (source)
677 The list of valid sources is available:
679 | OpenTX Version | Radio |
680 |----------------|-------|
681 | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) |
682 | 2.1 | [X9D and X9D+](http://downloads-21.open-tx.org/firmware/lua_fields_taranis.txt), [X9E](http://downloads-21.open-tx.org/firmware/lua_fields_taranis_x9e.txt) |
683 | 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/firmware/lua_fields_x12s.txt) |
685 @param name (string) name of the field
687 @retval table information about requested field, table elements:
688 * `id` (number) field identifier
689 * `name` (string) field name
690 * `desc` (string) field description
691 * 'unit' (number) unit identifier [Full list](../appendix/units.html)
693 @retval nil the requested field was not found
695 @status current Introduced in 2.0.8, 'unit' field added in 2.2.0
697 static int luaGetFieldInfo(lua_State
* L
)
699 const char * what
= luaL_checkstring(L
, 1);
701 bool found
= luaFindFieldByName(what
, field
, FIND_FIELD_DESC
);
704 lua_pushtableinteger(L
, "id", field
.id
);
705 lua_pushtablestring(L
, "name", what
);
706 lua_pushtablestring(L
, "desc", field
.desc
);
707 if (field
.id
>= MIXSRC_FIRST_TELEM
&& field
.id
<= MIXSRC_LAST_TELEM
) {
708 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[(int)((field
.id
-MIXSRC_FIRST_TELEM
)/3)];
709 lua_pushtableinteger(L
, "unit", telemetrySensor
.unit
);
712 lua_pushtablenil(L
, "unit");
720 @function getValue(source)
722 Returns the value of a source.
724 The list of fixed sources:
726 | OpenTX Version | Radio |
727 |----------------|-------|
728 | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) |
729 | 2.1 | [X9D and X9D+](http://downloads-21.open-tx.org/firmware/lua_fields_taranis.txt), [X9E](http://downloads-21.open-tx.org/firmware/lua_fields_taranis_x9e.txt) |
730 | 2.2 | [X9D and X9D+](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9d.txt), [X9E](http://downloads.open-tx.org/2.2/firmware/lua_fields_x9e.txt), [Horus](http://downloads.open-tx.org/2.2/firmware/lua_fields_x12s.txt) |
733 In OpenTX 2.1.x the telemetry sources no longer have a predefined name.
734 To get a telemetry value simply use it's sensor name. For example:
735 * Altitude sensor has a name "Alt"
736 * to get the current altitude use the source "Alt"
737 * to get the minimum altitude use the source "Alt-", to get the maximum use "Alt+"
739 @param source can be an identifier (number) (which was obtained by the getFieldInfo())
740 or a name (string) of the source.
742 @retval value current source value (number). Zero is returned for:
743 * non-existing sources
744 * for all telemetry source when the telemetry stream is not received
745 * far all non allowed sensors while FAI MODE is active
747 @retval table GPS position is returned in a table:
748 * `lat` (number) latitude, positive is North
749 * `lon` (number) longitude, positive is East
750 * `pilot-lat` (number) pilot latitude, positive is North
751 * `pilot-lon` (number) pilot longitude, positive is East
753 @retval table GPS date/time, see getDateTime()
755 @retval table Cells are returned in a table
756 (except where no cells were detected in which
757 case the returned value is 0):
758 * table has one item for each detected cell:
759 * key (number) cell number (1 to number of cells)
760 * value (number) current cell voltage
762 @status current Introduced in 2.0.0, changed in 2.1.0, `Cels+` and
763 `Cels-` added in 2.1.9
765 @notice Getting a value by its numerical identifier is faster then by its name.
766 While `Cels` sensor returns current values of all cells in a table, a `Cels+` or
767 `Cels-` will return a single value - the maximum or minimum Cels value.
769 static int luaGetValue(lua_State
* L
)
772 if (lua_isnumber(L
, 1)) {
773 src
= luaL_checkinteger(L
, 1);
776 // convert from field name to its id
777 const char *name
= luaL_checkstring(L
, 1);
779 bool found
= luaFindFieldByName(name
, field
);
784 luaGetValueAndPush(L
, src
);
791 Return the RAS value or nil if no valid hardware found
793 @retval number representing RAS value. Value bellow 0x33 (51 decimal) are all ok, value above 0x33 indicate a hardware antenna issue.
794 This is just a hardware pass/fail measure and does not represent the quality of the radio link
796 @notice RAS was called SWR in the past
798 @status current Introduced in 2.2.0
800 static int luaGetRAS(lua_State
* L
)
802 if (isRasValueValid()) {
803 lua_pushinteger(L
, telemetryData
.swrInternal
.value());
814 Return the internal GPS position or nil if no valid hardware found
816 @retval table representing the current radio position
817 * `lat` (number) internal GPS latitude, positive is North
818 * `lon` (number) internal GPS longitude, positive is East
819 * 'numsat' (number) current number of sats locked in by the GPS sensor
820 * 'fix' (boolean) fix status
821 * 'alt' (number) internal GPS altitude in 0.1m
822 * 'speed' (number) internal GPSspeed in 0.1m/s
823 * 'heading' (number) internal GPS ground course estimation in degrees * 10
824 * 'hdop' (number) internal GPS horizontal dilution of precision
826 @status current Introduced in 2.2.2
828 static int luaGetTxGPS(lua_State
* L
)
830 #if defined(INTERNAL_GPS)
831 lua_createtable(L
, 0, 7);
832 lua_pushtablenumber(L
, "lat", gpsData
.latitude
* 0.000001);
833 lua_pushtablenumber(L
, "lon", gpsData
.longitude
* 0.000001);
834 lua_pushtableinteger(L
, "numsat", gpsData
.numSat
);
835 lua_pushtableinteger(L
, "alt", gpsData
.altitude
);
836 lua_pushtableinteger(L
, "speed", gpsData
.speed
);
837 lua_pushtableinteger(L
, "heading", gpsData
.groundCourse
);
838 lua_pushtableinteger(L
, "hdop", gpsData
.hdop
);
840 lua_pushtableboolean(L
, "fix", true);
842 lua_pushtableboolean(L
, "fix", false);
851 @function getFlightMode(mode)
853 Return flight mode data.
855 @param mode (number) flight mode number to return (0 - 8). If mode parameter
856 is not specified (or contains invalid value), then the current flight mode data is returned.
858 @retval multiple returns 2 values:
859 * (number) (current) flight mode number (0 - 8)
860 * (string) (current) flight mode name
862 @status current Introduced in 2.1.7
864 static int luaGetFlightMode(lua_State
* L
)
866 int mode
= luaL_optinteger(L
, 1, -1);
867 if (mode
< 0 || mode
>= MAX_FLIGHT_MODES
) {
868 mode
= mixerCurrentFlightMode
;
870 lua_pushnumber(L
, mode
);
871 char name
[sizeof(g_model
.flightModeData
[0].name
)+1];
872 zchar2str(name
, g_model
.flightModeData
[mode
].name
, sizeof(g_model
.flightModeData
[0].name
));
873 lua_pushstring(L
, name
);
878 @function playFile(name)
880 Play a file from the SD card
882 @param path (string) full path to wav file (i.e. “/SOUNDS/en/system/tada.wav”)
883 Introduced in 2.1.0: If you use a relative path, the current language is appended
884 to the path (example: for English language: `/SOUNDS/en` is appended)
886 @status current Introduced in 2.0.0, changed in 2.1.0
888 static int luaPlayFile(lua_State
* L
)
890 const char * filename
= luaL_checkstring(L
, 1);
891 if (filename
[0] != '/') {
892 // relative sound file path - use current language dir for absolute path
893 char file
[AUDIO_FILENAME_MAXLEN
+1];
894 char * str
= getAudioPath(file
);
895 strncpy(str
, filename
, AUDIO_FILENAME_MAXLEN
- (str
-file
));
896 file
[AUDIO_FILENAME_MAXLEN
] = 0;
897 PLAY_FILE(file
, 0, 0);
900 PLAY_FILE(filename
, 0, 0);
906 @function playNumber(value, unit [, attributes])
908 Play a numerical value (text to speech)
910 @param value (number) number to play. Value is interpreted as integer.
912 @param unit (number) unit identifier [Full list]((../appendix/units.html))
914 @param attributes (unsigned number) possible values:
915 * `0 or not present` plays integral part of the number (for a number 123 it plays 123)
916 * `PREC1` plays a number with one decimal place (for a number 123 it plays 12.3)
917 * `PREC2` plays a number with two decimal places (for a number 123 it plays 1.23)
919 @status current Introduced in 2.0.0
922 static int luaPlayNumber(lua_State
* L
)
924 int number
= luaL_checkinteger(L
, 1);
925 int unit
= luaL_checkinteger(L
, 2);
926 unsigned int att
= luaL_optunsigned(L
, 3, 0);
927 playNumber(number
, unit
, att
, 0);
932 @function playDuration(duration [, hourFormat])
934 Play a time value (text to speech)
936 @param duration (number) number of seconds to play. Only integral part is used.
938 @param hourFormat (number):
939 * `0 or not present` play format: minutes and seconds.
940 * `!= 0` play format: hours, minutes and seconds.
942 @status current Introduced in 2.1.0
944 static int luaPlayDuration(lua_State
* L
)
946 int duration
= luaL_checkinteger(L
, 1);
947 bool playTime
= (luaL_optinteger(L
, 2, 0) != 0);
948 playDuration(duration
, playTime
? PLAY_TIME
: 0, 0);
953 @function playTone(frequency, duration, pause [, flags [, freqIncr]])
957 @param frequency (number) tone frequency in Hz (from 150 to 15000)
959 @param duration (number) length of the tone in milliseconds
961 @param pause (number) length of the silence after the tone in milliseconds
963 @param flags (number):
964 * `0 or not present` play with normal priority.
965 * `PLAY_BACKGROUND` play in background (built in vario function uses this context)
966 * `PLAY_NOW` play immediately
968 @param freqIncr (number) positive number increases the tone pitch (frequency with time),
969 negative number decreases it. The frequency changes every 10 milliseconds, the change is `freqIncr * 10Hz`.
970 The valid range is from -127 to 127.
972 @status current Introduced in 2.1.0
974 static int luaPlayTone(lua_State
* L
)
976 int frequency
= luaL_checkinteger(L
, 1);
977 int length
= luaL_checkinteger(L
, 2);
978 int pause
= luaL_checkinteger(L
, 3);
979 int flags
= luaL_optinteger(L
, 4, 0);
980 int freqIncr
= luaL_optinteger(L
, 5, 0);
981 audioQueue
.playTone(frequency
, length
, pause
, flags
, freqIncr
);
986 @function playHaptic(duration, pause [, flags])
988 Generate haptic feedback
990 @param duration (number) length of the haptic feedback in milliseconds
992 @param pause (number) length of the silence after haptic feedback in milliseconds
994 @param flags (number):
995 * `0 or not present` play with normal priority
996 * `PLAY_NOW` play immediately
998 @status current Introduced in 2.2.0
1000 static int luaPlayHaptic(lua_State
* L
)
1003 int length
= luaL_checkinteger(L
, 1);
1004 int pause
= luaL_checkinteger(L
, 2);
1005 int flags
= luaL_optinteger(L
, 3, 0);
1006 haptic
.play(length
, pause
, flags
);
1014 @function killEvents(key)
1016 Stops key state machine. See [Key Events](../key_events.md) for the detailed description.
1018 @param key (number) key to be killed, can also include event type (only the key part is used)
1020 @status current Introduced in 2.0.0
1023 static int luaKillEvents(lua_State
* L
)
1025 uint8_t key
= EVT_KEY_MASK(luaL_checkinteger(L
, 1));
1026 // prevent killing maskable keys (only in telemetry scripts)
1027 // TODO add which tpye of script is running before p_call()
1028 if (IS_MASKABLE(key
)) {
1034 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1038 Returns gray value which can be used in LCD functions
1040 @retval (number) a value that represents amount of *greyness* (from 0 to 15)
1042 @notice Only available on Taranis
1044 @status current Introduced in 2.0.13
1046 static int luaGrey(lua_State
* L
)
1048 int index
= luaL_checkinteger(L
, 1);
1049 lua_pushunsigned(L
, GREY(index
));
1055 @function getGeneralSettings()
1057 Returns (some of) the general radio settings
1059 @retval table with elements:
1060 * `battWarn` (number) radio battery range - warning value
1061 * `battMin` (number) radio battery range - minimum value
1062 * `battMax` (number) radio battery range - maximum value
1063 * `imperial` (number) set to a value different from 0 if the radio is set to the
1065 * `language` (string) radio language (used for menus)
1066 * `voice` (string) voice language (used for speech)
1067 * `gtimer` (number) radio global timer in seconds (does not include current session)
1069 @status current Introduced in 2.0.6, `imperial` added in TODO,
1070 `language` and `voice` added in 2.2.0, gtimer added in 2.2.2.
1073 static int luaGetGeneralSettings(lua_State
* L
)
1076 lua_pushtablenumber(L
, "battWarn", (g_eeGeneral
.vBatWarn
) * 0.1f
);
1077 lua_pushtablenumber(L
, "battMin", (90+g_eeGeneral
.vBatMin
) * 0.1f
);
1078 lua_pushtablenumber(L
, "battMax", (120+g_eeGeneral
.vBatMax
) * 0.1f
);
1079 lua_pushtableinteger(L
, "imperial", g_eeGeneral
.imperial
);
1080 lua_pushtablestring(L
, "language", TRANSLATIONS
);
1081 lua_pushtablestring(L
, "voice", currentLanguagePack
->id
);
1082 lua_pushtableinteger(L
, "gtimer", g_eeGeneral
.globalTimer
);
1087 @function getGlobalTimer()
1089 Returns radio timers
1091 @retval table with elements:
1092 * `gtimer` (number) radio global timer in seconds
1093 * `session` (number) radio session in seconds
1094 * `ttimer` (number) radio throttle timer in seconds
1095 * `tptimer` (number) radio throttle percent timer in seconds
1097 @status current Introduced added in 2.3.0.
1100 static int luaGetGlobalTimer(lua_State
* L
)
1103 lua_pushtableinteger(L
, "total", g_eeGeneral
.globalTimer
+ sessionTimer
);
1104 lua_pushtableinteger(L
, "session", sessionTimer
);
1105 lua_pushtableinteger(L
, "throttle", s_timeCumThr
);
1106 lua_pushtableinteger(L
, "throttlepct", s_timeCum16ThrP
/16);
1111 @function popupInput(title, event, input, min, max)
1113 Raises a pop-up on screen that allows uses input
1115 @param title (string) text to display
1117 @param event (number) the event variable that is passed in from the
1118 Run function (key pressed)
1120 @param input (number) value that can be adjusted by the +/- keys
1122 @param min (number) min value that input can reach (by pressing the - key)
1124 @param max (number) max value that input can reach
1126 @retval number result of the input adjustment
1128 @retval "OK" user pushed ENT key
1130 @retval "CANCEL" user pushed EXIT key
1132 @notice Use only from stand-alone and telemetry scripts.
1134 @status current Introduced in 2.0.0
1137 /* TODO : fix, broken by popups rewrite
1138 static int luaPopupInput(lua_State * L)
1140 event_t event = luaL_checkinteger(L, 2);
1141 warningInputValue = luaL_checkinteger(L, 3);
1142 warningInputValueMin = luaL_checkinteger(L, 4);
1143 warningInputValueMax = luaL_checkinteger(L, 5);
1144 warningText = luaL_checkstring(L, 1);
1145 warningType = WARNING_TYPE_INPUT;
1146 runPopupWarning(event);
1147 if (warningResult) {
1149 lua_pushstring(L, "OK");
1151 else if (!warningText) {
1152 lua_pushstring(L, "CANCEL");
1155 lua_pushinteger(L, warningInputValue);
1163 @function popupWarning(title, event)
1165 Raises a pop-up on screen that shows a warning
1167 @param title (string) text to display
1169 @param event (number) the event variable that is passed in from the
1170 Run function (key pressed)
1172 @retval "CANCEL" user pushed EXIT key
1174 @notice Use only from stand-alone and telemetry scripts.
1176 @status current Introduced in 2.2.0
1178 static int luaPopupWarning(lua_State
* L
)
1180 event_t event
= luaL_checkinteger(L
, 2);
1181 warningText
= luaL_checkstring(L
, 1);
1182 warningType
= WARNING_TYPE_ASTERISK
;
1183 runPopupWarning(event
);
1185 lua_pushstring(L
, "CANCEL");
1195 @function popupConfirmation(title, event)
1197 Raises a pop-up on screen that asks for confirmation
1199 @param title (string) text to display
1201 @param event (number) the event variable that is passed in from the
1202 Run function (key pressed)
1204 @retval "CANCEL" user pushed EXIT key
1206 @notice Use only from stand-alone and telemetry scripts.
1208 @status current Introduced in 2.2.0
1210 static int luaPopupConfirmation(lua_State
* L
)
1212 event_t event
= luaL_checkinteger(L
, 2);
1213 warningText
= luaL_checkstring(L
, 1);
1214 warningType
= WARNING_TYPE_CONFIRM
;
1215 runPopupWarning(event
);
1217 lua_pushstring(L
, warningResult
? "OK" : "CANCEL");
1227 @function defaultStick(channel)
1229 Get stick that is assigned to a channel. See Default Channel Order in General Settings.
1231 @param channel (number) channel number (0 means CH1)
1233 @retval number Stick assigned to this channel (from 0 to 3)
1235 @status current Introduced in 2.0.0
1237 static int luaDefaultStick(lua_State
* L
)
1239 uint8_t channel
= luaL_checkinteger(L
, 1);
1240 lua_pushinteger(L
, channelOrder(channel
+1)-1);
1245 @function setTelemetryValue(id, subID, instance, value [, unit [, precision [, name]]])
1247 @param id Id of the sensor, valid range is from 0 to 0xFFFF
1249 @param subID subID of the sensor, usually 0, valid range is from 0 to 7
1251 @param instance instance of the sensor (SensorID), valid range is from 0 to 0xFF
1253 @param value fed to the sensor
1255 @param unit unit of the sensor [Full list](../appendix/units.html)
1257 @param precision the precision of the sensor
1258 * `0 or not present` no decimal precision.
1259 * `!= 0` value is divided by 10^precision, e.g. value=1000, prec=2 => 10.00.
1261 @param name (string) Name of the sensor if it does not yet exist (4 chars).
1262 * `not present` Name defaults to the Id.
1263 * `present` Sensor takes name of the argument. Argument must have name surrounded by quotes: e.g., "Name"
1265 @retval true, if the sensor was just added. In this case the value is ignored (subsequent call will set the value)
1267 @notice All three parameters `id`, `subID` and `instance` can't be zero at the same time. At least one of them
1268 must be different from zero.
1270 @status current Introduced in 2.2.0
1272 static int luaSetTelemetryValue(lua_State
* L
)
1274 uint16_t id
= luaL_checkunsigned(L
, 1);
1275 uint8_t subId
= luaL_checkunsigned(L
, 2) & 0x7;
1276 uint8_t instance
= luaL_checkunsigned(L
, 3);
1277 int32_t value
= luaL_checkinteger(L
, 4);
1278 uint32_t unit
= luaL_optunsigned(L
, 5, 0);
1279 uint32_t prec
= luaL_optunsigned(L
, 6, 0);
1282 const char* name
= luaL_optstring(L
, 7, NULL
);
1283 if (name
!= NULL
&& strlen(name
) > 0) {
1284 str2zchar(zname
, name
, 4);
1287 zname
[0] = hex2zchar((id
& 0xf000) >> 12);
1288 zname
[1] = hex2zchar((id
& 0x0f00) >> 8);
1289 zname
[2] = hex2zchar((id
& 0x00f0) >> 4);
1290 zname
[3] = hex2zchar((id
& 0x000f) >> 0);
1292 if (id
| subId
| instance
) {
1293 int index
= setTelemetryValue(PROTOCOL_TELEMETRY_LUA
, id
, subId
, instance
, value
, unit
, prec
);
1295 TelemetrySensor
&telemetrySensor
= g_model
.telemetrySensors
[index
];
1296 telemetrySensor
.id
= id
;
1297 telemetrySensor
.subId
= subId
;
1298 telemetrySensor
.instance
= instance
;
1299 telemetrySensor
.init(zname
, unit
, prec
);
1300 lua_pushboolean(L
, true);
1303 lua_pushboolean(L
, false);
1307 lua_pushboolean(L
, false);
1312 @function defaultChannel(stick)
1314 Get channel assigned to stick. See Default Channel Order in General Settings
1316 @param stick (number) stick number (from 0 to 3)
1318 @retval number channel assigned to this stick (from 0 to 3)
1320 @retval nil stick not found
1322 @status current Introduced in 2.0.0
1324 static int luaDefaultChannel(lua_State
* L
)
1326 uint8_t stick
= luaL_checkinteger(L
, 1);
1327 for (int i
=1; i
<=4; i
++) {
1328 int tmp
= channelOrder(i
) - 1;
1330 lua_pushinteger(L
, i
-1);
1341 Get RSSI value as well as low and critical RSSI alarm levels (in dB)
1343 @retval rssi RSSI value (0 if no link)
1345 @retval alarm_low Configured low RSSI alarm level
1347 @retval alarm_crit Configured critical RSSI alarm level
1349 @status current Introduced in 2.2.0
1351 static int luaGetRSSI(lua_State
* L
)
1353 lua_pushunsigned(L
, min((uint8_t)99, TELEMETRY_RSSI()));
1354 lua_pushunsigned(L
, g_model
.rssiAlarms
.getWarningRssi());
1355 lua_pushunsigned(L
, g_model
.rssiAlarms
.getCriticalRssi());
1360 @function chdir(directory)
1362 Change the working directory
1364 @param directory (string) New working directory
1366 @status current Introduced in 2.3.0
1370 static int luaChdir(lua_State
* L
)
1372 const char * directory
= luaL_optstring(L
, 1, nullptr);
1378 @function loadScript(file [, mode], [,env])
1380 Load a Lua script file. This is similar to Lua's own [loadfile()](https://www.lua.org/manual/5.2/manual.html#pdf-loadfile)
1381 API method, but it uses OpenTx's optional pre-compilation feature to save memory and time during load.
1383 Return values are same as from Lua API loadfile() method: If the script was loaded w/out errors
1384 then the loaded script (or "chunk") is returned as a function. Otherwise, returns nil plus the error message.
1386 @param file (string) Full path and file name of script. The file extension is optional and ignored (see `mode` param to control
1387 which extension will be used). However, if an extension is specified, it should be ".lua" (or ".luac"), otherwise it is treated
1388 as part of the file name and the .lua/.luac will be appended to that.
1390 @param mode (string) (optional) Controls whether to force loading the text (.lua) or pre-compiled binary (.luac)
1391 version of the script. By default OTx will load the newest version and compile a new binary if necessary (overwriting any
1392 existing .luac version of the same script, and stripping some debug info like line numbers).
1393 You can use `mode` to control the loading behavior more specifically. Possible values are:
1396 * `T` (default on simulator) prefer text but load binary if that is the only version available.
1397 * `bt` (default on radio) either binary or text, whichever is newer (binary preferred when timestamps are equal).
1398 * Add `x` to avoid automatic compilation of source file to .luac version.
1399 Eg: "tx", "bx", or "btx".
1400 * Add `c` to force compilation of source file to .luac version (even if existing version is newer than source file).
1401 Eg: "tc" or "btc" (forces "t", overrides "x").
1402 * Add `d` to keep extra debug info in the compiled binary.
1403 Eg: "td", "btd", or "tcd" (no effect with just "b" or with "x").
1406 Note that you will get an error if you specify `mode` as "b" or "t" and that specific version of the file does not exist (eg. no .luac file when "b" is used).
1407 Also note that `mode` is NOT passed on to Lua's loader function, so unlike with loadfile() the actual file content is not checked (as if no mode or "bt" were passed to loadfile()).
1409 @param env (integer) See documentation for Lua function loadfile().
1411 @retval function The loaded script, or `nil` if there was an error (e.g. file not found or syntax error).
1413 @retval string Error message(s), if any. Blank if no error occurred.
1415 @status current Introduced in 2.2.0
1420 fun, err = loadScript("/SCRIPTS/FUNCTIONS/print.lua")
1421 if (fun ~= nil) then
1422 fun("Hello from loadScript()")
1429 static int luaLoadScript(lua_State
* L
)
1431 // this function is replicated pretty much verbatim from luaB_loadfile() and load_aux() in lbaselib.c
1432 const char *fname
= luaL_optstring(L
, 1, NULL
);
1433 const char *mode
= luaL_optstring(L
, 2, NULL
);
1434 int env
= (!lua_isnone(L
, 3) ? 3 : 0); // 'env' index or 0 if no 'env'
1436 if (fname
!= NULL
&& luaLoadScriptFileToState(L
, fname
, mode
) == SCRIPT_OK
) {
1437 if (env
!= 0) { // 'env' parameter?
1438 lua_pushvalue(L
, env
); // environment for loaded function
1439 if (!lua_setupvalue(L
, -2, 1)) // set it as 1st upvalue
1440 lua_pop(L
, 1); // remove 'env' if not used by previous call
1445 // error (message should be on top of the stack)
1446 if (!lua_isstring(L
, -1)) {
1447 // probably didn't find a file or had some other error before luaL_loadfile() was run
1448 lua_pushfstring(L
, "loadScript(\"%s\", \"%s\") error: File not found", (fname
!= NULL
? fname
: "nul"), (mode
!= NULL
? mode
: "bt"));
1451 lua_insert(L
, -2); // move nil before error message
1452 return 2; // return nil plus error message
1457 @function getUsage()
1459 Get percent of already used Lua instructions in current script execution cycle.
1461 @retval usage (number) a value from 0 to 100 (percent)
1463 @status current Introduced in 2.2.1
1465 static int luaGetUsage(lua_State
* L
)
1467 lua_pushinteger(L
, instructionsPercent
);
1472 @function resetGlobalTimer([type])
1474 Resets the radio global timer to 0.
1476 @param (optional) : if set to 'all', throttle ,throttle percent and session timers are reset too
1477 if set to 'session', radio session timer is reset too
1478 if set to 'ttimer', radio throttle timer is reset too
1479 if set to 'tptimer', radio throttle percent timer is reset too
1481 @status current Introduced in 2.2.2, param added in 2.3
1483 static int luaResetGlobalTimer(lua_State
* L
)
1486 const char * option
= luaL_optlstring(L
, 1, "total", &length
);
1487 if (!strcmp(option
, "all")) {
1488 g_eeGeneral
.globalTimer
= 0;
1491 s_timeCum16ThrP
= 0;
1493 else if (!strcmp(option
, "total")) {
1494 g_eeGeneral
.globalTimer
= 0;
1497 else if (!strcmp(option
, "session")) {
1500 else if (!strcmp(option
, "throttle")) {
1503 else if (!strcmp(option
, "throttlepct")) {
1504 s_timeCum16ThrP
= 0;
1506 storageDirty(EE_GENERAL
);
1511 @function multiBuffer(address[,value])
1513 This function reads/writes the Multi protocol buffer to interact with a protocol².
1515 @param address to read/write in the buffer
1516 @param (optional): value to write in the buffer
1518 @retval buffer value (number)
1520 @status current Introduced in 2.3.2
1522 #if defined(MULTIMODULE)
1523 uint8_t * Multi_Buffer
= nullptr;
1525 static int luaMultiBuffer(lua_State
* L
)
1527 uint8_t address
= luaL_checkunsigned(L
, 1);
1529 Multi_Buffer
= (uint8_t *) malloc(MULTI_BUFFER_SIZE
);
1531 if (!Multi_Buffer
|| address
>= MULTI_BUFFER_SIZE
) {
1532 lua_pushinteger(L
, 0);
1535 uint16_t value
= luaL_optunsigned(L
, 2, 0x100);
1536 if (value
< 0x100) {
1537 Multi_Buffer
[address
] = value
;
1539 lua_pushinteger(L
, Multi_Buffer
[address
]);
1545 @function serialWrite(str)
1546 @param str (string) String to be written to the serial port.
1548 Writes a string to the serial port. The string is allowed to contain any character, including 0.
1550 @status current Introduced in TODO
1552 static int luaSerialWrite(lua_State
* L
)
1554 const char * str
= luaL_checkstring(L
, 1);
1555 size_t len
= lua_rawlen(L
, 1);
1557 if (!str
|| len
< 1)
1561 #if defined(USB_SERIAL)
1562 if (getSelectedUsbMode() == USB_SERIAL_MODE
) {
1563 size_t wr_len
= len
;
1564 const char* p
= str
;
1565 while(wr_len
--) usbSerialPutc(*p
++);
1568 #if defined(AUX_SERIAL)
1569 if (auxSerialMode
== UART_MODE_LUA
) {
1570 size_t wr_len
= len
;
1571 const char* p
= str
;
1572 while(wr_len
--) auxSerialPutc(*p
++);
1576 debugPrintf("luaSerialWrite: %.*s",len
,str
);
1582 const luaL_Reg opentxLib
[] = {
1583 { "getTime", luaGetTime
},
1584 { "getDateTime", luaGetDateTime
},
1585 #if defined(RTCLOCK)
1586 { "getRtcTime", luaGetRtcTime
},
1588 { "getVersion", luaGetVersion
},
1589 { "getGeneralSettings", luaGetGeneralSettings
},
1590 { "getGlobalTimer", luaGetGlobalTimer
},
1591 { "getValue", luaGetValue
},
1592 { "getRAS", luaGetRAS
},
1593 { "getTxGPS", luaGetTxGPS
},
1594 { "getFieldInfo", luaGetFieldInfo
},
1595 { "getFlightMode", luaGetFlightMode
},
1596 { "playFile", luaPlayFile
},
1597 { "playNumber", luaPlayNumber
},
1598 { "playDuration", luaPlayDuration
},
1599 { "playTone", luaPlayTone
},
1600 { "playHaptic", luaPlayHaptic
},
1601 // { "popupInput", luaPopupInput },
1602 { "popupWarning", luaPopupWarning
},
1603 { "popupConfirmation", luaPopupConfirmation
},
1604 { "defaultStick", luaDefaultStick
},
1605 { "defaultChannel", luaDefaultChannel
},
1606 { "getRSSI", luaGetRSSI
},
1607 { "killEvents", luaKillEvents
},
1608 { "chdir", luaChdir
},
1609 { "loadScript", luaLoadScript
},
1610 { "getUsage", luaGetUsage
},
1611 { "resetGlobalTimer", luaResetGlobalTimer
},
1612 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1613 { "GREY", luaGrey
},
1616 { "accessTelemetryPush", luaAccessTelemetryPush
},
1618 { "sportTelemetryPop", luaSportTelemetryPop
},
1619 { "sportTelemetryPush", luaSportTelemetryPush
},
1620 { "setTelemetryValue", luaSetTelemetryValue
},
1621 #if defined(CROSSFIRE)
1622 { "crossfireTelemetryPop", luaCrossfireTelemetryPop
},
1623 { "crossfireTelemetryPush", luaCrossfireTelemetryPush
},
1625 #if defined(MULTIMODULE)
1626 { "multiBuffer", luaMultiBuffer
},
1628 { "serialWrite", luaSerialWrite
},
1629 { nullptr, nullptr } /* sentinel */
1632 const luaR_value_entry opentxConstants
[] = {
1633 { "FULLSCALE", RESX
},
1634 { "XXLSIZE", XXLSIZE
},
1635 { "DBLSIZE", DBLSIZE
},
1636 { "MIDSIZE", MIDSIZE
},
1637 { "SMLSIZE", SMLSIZE
},
1638 { "INVERS", INVERS
},
1643 { "CENTER", CENTERED
},
1646 { "VALUE", INPUT_TYPE_VALUE
},
1647 { "SOURCE", INPUT_TYPE_SOURCE
},
1648 { "REPLACE", MLTPX_REP
},
1649 { "MIXSRC_FIRST_INPUT", MIXSRC_FIRST_INPUT
},
1650 { "MIXSRC_Rud", MIXSRC_Rud
},
1651 { "MIXSRC_Ele", MIXSRC_Ele
},
1652 { "MIXSRC_Thr", MIXSRC_Thr
},
1653 { "MIXSRC_Ail", MIXSRC_Ail
},
1654 { "MIXSRC_SA", MIXSRC_SA
},
1655 { "MIXSRC_SB", MIXSRC_SB
},
1656 { "MIXSRC_SC", MIXSRC_SC
},
1657 { "MIXSRC_SD", MIXSRC_SD
},
1658 #if !defined(PCBX7) && !defined(PCBXLITE) && !defined(PCBX9LITE)
1659 { "MIXSRC_SE", MIXSRC_SE
},
1660 { "MIXSRC_SG", MIXSRC_SG
},
1662 #if !defined(PCBXLITE) && !defined(PCBX9LITE)
1663 { "MIXSRC_SF", MIXSRC_SF
},
1664 { "MIXSRC_SH", MIXSRC_SH
},
1666 { "MIXSRC_CH1", MIXSRC_CH1
},
1667 { "SWSRC_LAST", SWSRC_LAST_LOGICAL_SWITCH
},
1668 { "MAX_SENSORS", MAX_TELEMETRY_SENSORS
},
1669 #if defined(COLORLCD)
1670 { "SHADOWED", SHADOWED
},
1671 { "COLOR", ZoneOption::Color
},
1672 { "BOOL", ZoneOption::Bool
},
1673 { "STRING", ZoneOption::String
},
1674 { "CUSTOM_COLOR", CUSTOM_COLOR
},
1675 { "TEXT_COLOR", TEXT_COLOR
},
1676 { "TEXT_BGCOLOR", TEXT_BGCOLOR
},
1677 { "TEXT_INVERTED_COLOR", TEXT_INVERTED_COLOR
},
1678 { "TEXT_INVERTED_BGCOLOR", TEXT_INVERTED_BGCOLOR
},
1679 { "LINE_COLOR", LINE_COLOR
},
1680 { "SCROLLBOX_COLOR", SCROLLBOX_COLOR
},
1681 { "MENU_TITLE_BGCOLOR", MENU_TITLE_BGCOLOR
},
1682 { "MENU_TITLE_COLOR", MENU_TITLE_COLOR
},
1683 { "MENU_TITLE_DISABLE_COLOR", MENU_TITLE_DISABLE_COLOR
},
1684 { "ALARM_COLOR", ALARM_COLOR
},
1685 { "WARNING_COLOR", WARNING_COLOR
},
1686 { "TEXT_DISABLE_COLOR", TEXT_DISABLE_COLOR
},
1687 { "HEADER_COLOR", HEADER_COLOR
},
1688 { "CURVE_AXIS_COLOR", CURVE_AXIS_COLOR
},
1689 { "CURVE_COLOR", CURVE_COLOR
},
1690 { "CURVE_CURSOR_COLOR", CURVE_CURSOR_COLOR
},
1691 { "TITLE_BGCOLOR", TITLE_BGCOLOR
},
1692 { "TRIM_BGCOLOR", TRIM_BGCOLOR
},
1693 { "TRIM_SHADOW_COLOR", TRIM_SHADOW_COLOR
},
1694 { "MAINVIEW_PANES_COLOR", MAINVIEW_PANES_COLOR
},
1695 { "MAINVIEW_GRAPHICS_COLOR", MAINVIEW_GRAPHICS_COLOR
},
1696 { "HEADER_BGCOLOR", HEADER_BGCOLOR
},
1697 { "HEADER_ICON_BGCOLOR", HEADER_ICON_BGCOLOR
},
1698 { "HEADER_CURRENT_BGCOLOR", HEADER_CURRENT_BGCOLOR
},
1699 { "OVERLAY_COLOR", OVERLAY_COLOR
},
1700 { "MENU_HEADER_HEIGHT", MENU_HEADER_HEIGHT
},
1701 { "WHITE", (double)WHITE
},
1702 { "GREY", (double)GREY
},
1703 { "DARKGREY", (double)DARKGREY
},
1704 { "BLACK", (double)BLACK
},
1705 { "YELLOW", (double)YELLOW
},
1706 { "BLUE", (double)BLUE
},
1707 { "LIGHTGREY", (double)LIGHTGREY
},
1708 { "RED", (double)RED
},
1709 { "DARKRED", (double)DARKRED
},
1711 { "FIXEDWIDTH", FIXEDWIDTH
},
1715 #if defined(ROTARY_ENCODER_NAVIGATION)
1716 { "EVT_VIRTUAL_PREV", EVT_ROTARY_LEFT
},
1717 { "EVT_VIRTUAL_NEXT", EVT_ROTARY_RIGHT
},
1718 { "EVT_VIRTUAL_DEC", EVT_ROTARY_LEFT
},
1719 { "EVT_VIRTUAL_INC", EVT_ROTARY_RIGHT
},
1720 #elif defined(PCBX9D) || defined(PCBX9DP) // key reverted between field nav and value change
1721 { "EVT_VIRTUAL_PREV", EVT_KEY_FIRST(KEY_PLUS
) },
1722 { "EVT_VIRTUAL_PREV_REPT", EVT_KEY_REPT(KEY_PLUS
) },
1723 { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_MINUS
) },
1724 { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_MINUS
) },
1725 { "EVT_VIRTUAL_DEC", EVT_KEY_FIRST(KEY_MINUS
) },
1726 { "EVT_VIRTUAL_DEC_REPT", EVT_KEY_REPT(KEY_MINUS
) },
1727 { "EVT_VIRTUAL_INC", EVT_KEY_FIRST(KEY_PLUS
) },
1728 { "EVT_VIRTUAL_INC_REPT", EVT_KEY_REPT(KEY_PLUS
) },
1730 { "EVT_VIRTUAL_PREV", EVT_KEY_FIRST(KEY_UP
) },
1731 { "EVT_VIRTUAL_PREV_REPT", EVT_KEY_REPT(KEY_UP
) },
1732 { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_DOWN
) },
1733 { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_DOWN
) },
1734 { "EVT_VIRTUAL_DEC", EVT_KEY_FIRST(KEY_DOWN
) },
1735 { "EVT_VIRTUAL_DEC_REPT", EVT_KEY_REPT(KEY_DOWN
) },
1736 { "EVT_VIRTUAL_INC", EVT_KEY_FIRST(KEY_UP
) },
1737 { "EVT_VIRTUAL_INC_REPT", EVT_KEY_REPT(KEY_UP
) },
1740 #if defined(NAVIGATION_9X) || defined(NAVIGATION_XLITE)
1741 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_LEFT
) },
1742 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_LEFT
) },
1743 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_RIGHT
) },
1744 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_RIGHT
) },
1745 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1746 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1747 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1748 #elif defined(NAVIGATION_X7) || defined(NAVIGATION_X9D)
1749 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_PAGE
) },
1750 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PAGE
) },
1751 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MENU
) },
1752 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MENU
) },
1753 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1754 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1755 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1756 #elif defined(NAVIGATION_HORUS)
1757 #if defined(KEYS_GPIO_REG_PGUP)
1758 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_BREAK(KEY_PGUP
) },
1759 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PGDN
) },
1761 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_PGDN
) },
1762 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PGDN
) },
1764 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MODEL
) },
1765 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MODEL
) },
1766 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1767 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1768 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1771 #if defined(KEYS_GPIO_REG_EXIT)
1772 { "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT
) },
1775 #if defined(KEYS_GPIO_REG_ENTER)
1776 KEY_EVENTS(ENTER
, KEY_ENTER
),
1779 #if defined(KEYS_GPIO_REG_MENU)
1780 KEY_EVENTS(MENU
, KEY_MENU
),
1783 #if defined(KEYS_GPIO_REG_RIGHT) && defined(NAVIGATION_HORUS)
1784 KEY_EVENTS(TELEM
, KEY_TELEM
),
1785 #elif defined(KEYS_GPIO_REG_RIGHT)
1786 KEY_EVENTS(RIGHT
, KEY_RIGHT
),
1789 #if defined(KEYS_GPIO_REG_UP) && defined(NAVIGATION_HORUS)
1790 KEY_EVENTS(MODEL
, KEY_MODEL
),
1791 #elif defined(KEYS_GPIO_REG_UP)
1792 KEY_EVENTS(UP
, KEY_UP
),
1795 #if defined(KEYS_GPIO_REG_LEFT) && defined(NAVIGATION_HORUS)
1796 KEY_EVENTS(SYS
, KEY_RADIO
),
1797 #elif defined(KEYS_GPIO_REG_LEFT)
1798 KEY_EVENTS(LEFT
, KEY_LEFT
),
1801 #if defined(KEYS_GPIO_REG_DOWN) && defined(NAVIGATION_HORUS)
1802 { "EVT_RTN_FIRST", EVT_KEY_BREAK(KEY_EXIT
) },
1804 KEY_EVENTS(DOWN
, KEY_DOWN
),
1807 #if defined(KEYS_GPIO_REG_PGUP)
1808 KEY_EVENTS(PAGEUP
, KEY_PGUP
),
1811 #if defined(KEYS_GPIO_REG_PGDN)
1812 KEY_EVENTS(PAGEDN
, KEY_PGDN
),
1815 #if defined(KEYS_GPIO_REG_PAGE)
1816 KEY_EVENTS(PAGE
, KEY_PAGE
),
1819 #if defined(KEYS_GPIO_REG_SHIFT)
1820 KEY_EVENTS(SHIFT
, KEY_SHIFT
),
1823 #if defined(KEYS_GPIO_REG_PLUS)
1824 KEY_EVENTS(PLUS
, KEY_PLUS
),
1827 #if defined(KEYS_GPIO_REG_MINUS)
1828 KEY_EVENTS(MINUS
, KEY_MINUS
),
1831 #if defined(ROTARY_ENCODER_NAVIGATION)
1832 KEY_EVENTS(ROT
, KEY_ENTER
),
1833 { "EVT_ROT_LEFT", EVT_ROTARY_LEFT
},
1834 { "EVT_ROT_RIGHT", EVT_ROTARY_RIGHT
},
1837 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1838 { "FILL_WHITE", FILL_WHITE
},
1839 { "GREY_DEFAULT", GREY_DEFAULT
},
1849 { "DOTTED", DOTTED
},
1852 { "PLAY_NOW", PLAY_NOW
},
1853 { "PLAY_BACKGROUND", PLAY_BACKGROUND
},
1854 { "TIMEHOUR", TIMEHOUR
},
1856 #if defined(PCBHORUS)
1857 // Adding the unit consts for the set Telemetry function adds about 1k of flash usage
1858 {"UNIT_RAW", UNIT_RAW
},
1859 {"UNIT_VOLTS", UNIT_VOLTS
},
1860 {"UNIT_AMPS", UNIT_AMPS
},
1861 {"UNIT_MILLIAMPS", UNIT_MILLIAMPS
},
1862 {"UNIT_KTS", UNIT_KTS
},
1863 {"UNIT_METERS_PER_SECOND", UNIT_METERS_PER_SECOND
},
1864 {"UNIT_FEET_PER_SECOND", UNIT_FEET_PER_SECOND
},
1865 {"UNIT_KMH", UNIT_KMH
},
1866 {"UNIT_MPH", UNIT_MPH
},
1867 {"UNIT_METERS", UNIT_METERS
},
1868 {"UNIT_FEET", UNIT_FEET
},
1869 {"UNIT_CELSIUS", UNIT_CELSIUS
},
1870 {"UNIT_FAHRENHEIT", UNIT_FAHRENHEIT
},
1871 {"UNIT_PERCENT", UNIT_PERCENT
},
1872 {"UNIT_MAH", UNIT_MAH
},
1873 {"UNIT_WATTS", UNIT_WATTS
},
1874 {"UNIT_MILLIWATTS", UNIT_MILLIWATTS
},
1875 {"UNIT_DB", UNIT_DB
},
1876 {"UNIT_RPMS", UNIT_RPMS
},
1877 {"UNIT_G", UNIT_G
},
1878 {"UNIT_DEGREE", UNIT_DEGREE
},
1879 {"UNIT_RADIANS", UNIT_RADIANS
},
1880 {"UNIT_MILLILITERS", UNIT_MILLILITERS
},
1881 {"UNIT_FLOZ", UNIT_FLOZ
},
1882 {"UNIT_MILLILITERS_PER_MINUTE", UNIT_MILLILITERS_PER_MINUTE
},
1883 {"UNIT_HOURS", UNIT_HOURS
},
1884 {"UNIT_MINUTES", UNIT_MINUTES
},
1885 {"UNIT_SECONDS", UNIT_SECONDS
},
1886 {"UNIT_CELLS", UNIT_CELLS
},
1887 {"UNIT_DATETIME", UNIT_DATETIME
},
1888 {"UNIT_GPS", UNIT_GPS
},
1889 {"UNIT_BITFIELD", UNIT_BITFIELD
},
1890 {"UNIT_TEXT", UNIT_TEXT
},
1892 { nullptr, 0 } /* sentinel */