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(PCBX7ACCESS)
38 #include "lua/lua_exports_x7access.inc"
39 #elif defined(RADIO_X7)
40 #include "lua/lua_exports_x7.inc"
41 #elif defined(RADIO_T12)
42 #include "lua/lua_exports_t12.inc"
43 #elif defined(PCBX9LITES)
44 #include "lua/lua_exports_x9lites.inc"
45 #elif defined(PCBX9LITE)
46 #include "lua/lua_exports_x9lite.inc"
47 #elif defined(PCBXLITES)
48 #include "lua/lua_exports_xlites.inc"
49 #elif defined(PCBXLITE)
50 #include "lua/lua_exports_xlite.inc"
51 #elif defined(PCBTARANIS)
52 #include "lua/lua_exports_x9d.inc"
56 #define RADIO_VERSION FLAVOUR "-simu"
58 #define RADIO_VERSION FLAVOUR
61 #define FIND_FIELD_DESC 0x01
63 #define KEY_EVENTS(xxx, yyy) \
64 { "EVT_"#xxx"_FIRST", EVT_KEY_FIRST(yyy) }, \
65 { "EVT_"#xxx"_BREAK", EVT_KEY_BREAK(yyy) }, \
66 { "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \
67 { "EVT_"#xxx"_REPT", EVT_KEY_REPT(yyy) }
70 @function getVersion()
74 @retval string OpenTX version (ie "2.1.5")
76 @retval multiple (available since 2.1.7) returns 5 values:
77 * (string) OpenTX version (ie "2.1.5")
78 * (string) radio type: `x12s`, `x10`, `x9e`, `x9d+`, `x9d` or `x7`.
79 If running in simulator the "-simu" is added
80 * (number) major version (ie 2 if version 2.1.5)
81 * (number) minor version (ie 1 if version 2.1.5)
82 * (number) revision number (ie 5 if version 2.1.5)
84 @status current Introduced in 2.0.0, expanded in 2.1.7, radio type strings changed in 2.2.0
88 This example also runs in OpenTX versions where the function returned only one value:
91 local function run(event)
92 local ver, radio, maj, minor, rev = getVersion()
93 print("version: "..ver)
94 if radio then print ("radio: "..radio) end
95 if maj then print ("maj: "..maj) end
96 if minor then print ("minor: "..minor) end
97 if rev then print ("rev: "..rev) end
103 Output of the above script in simulator:
112 static int luaGetVersion(lua_State
* L
)
114 lua_pushstring(L
, VERSION
);
115 lua_pushstring(L
, RADIO_VERSION
);
116 lua_pushnumber(L
, VERSION_MAJOR
);
117 lua_pushnumber(L
, VERSION_MINOR
);
118 lua_pushnumber(L
, VERSION_REVISION
);
125 Return the time since the radio was started in multiple of 10ms
127 @retval number Number of 10ms ticks since the radio was started Example:
128 run time: 12.54 seconds, return value: 1254
130 The timer internally uses a 32-bit counter which is enough for 497 days so
131 overflows will not happen.
133 @status current Introduced in 2.0.0
135 static int luaGetTime(lua_State
* L
)
137 lua_pushunsigned(L
, get_tmr10ms());
141 static void luaPushDateTime(lua_State
* L
, uint32_t year
, uint32_t mon
, uint32_t day
,
142 uint32_t hour
, uint32_t min
, uint32_t sec
)
144 uint32_t hour12
= hour
;
149 else if (hour
> 12) {
152 lua_createtable(L
, 0, 8);
153 lua_pushtableinteger(L
, "year", year
);
154 lua_pushtableinteger(L
, "mon", mon
);
155 lua_pushtableinteger(L
, "day", day
);
156 lua_pushtableinteger(L
, "hour", hour
);
157 lua_pushtableinteger(L
, "min", min
);
158 lua_pushtableinteger(L
, "sec", sec
);
159 lua_pushtableinteger(L
, "hour12", hour12
);
161 lua_pushtablestring(L
, "suffix", "am");
164 lua_pushtablestring(L
, "suffix", "pm");
169 @function getDateTime()
171 Return current system date and time that is kept by the RTC unit
173 @retval table current date and time, table elements:
174 * `year` (number) year
175 * `mon` (number) month
176 * `day` (number) day of month
177 * `hour` (number) hours
178 * `hour12` (number) hours in US format
179 * `min` (number) minutes
180 * `sec` (number) seconds
181 * `suffix` (text) am or pm
183 static int luaGetDateTime(lua_State
* L
)
187 luaPushDateTime(L
, utm
.tm_year
+ TM_YEAR_BASE
, utm
.tm_mon
+ 1, utm
.tm_mday
, utm
.tm_hour
, utm
.tm_min
, utm
.tm_sec
);
192 @function getRtcTime()
194 Return current RTC system date as unix timstamp (in seconds since 1. Jan 1970)
196 Please note the RTC timestamp is kept internally as a 32bit integer, which will overflow
199 @retval number Number of seconds elapsed since 1. Jan 1970
203 static int luaGetRtcTime(lua_State
* L
)
205 lua_pushunsigned(L
, g_rtcTime
);
210 static void luaPushLatLon(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
211 /* result is lua table containing members ["lat"] and ["lon"] as lua_Number (doubles) in decimal degrees */
213 lua_createtable(L
, 0, 5);
214 lua_pushtablenumber(L
, "lat", telemetryItem
.gps
.latitude
* 0.000001); // floating point multiplication is faster than division
215 lua_pushtablenumber(L
, "pilot-lat", telemetryItem
.pilotLatitude
* 0.000001);
216 lua_pushtablenumber(L
, "lon", telemetryItem
.gps
.longitude
* 0.000001);
217 lua_pushtablenumber(L
, "pilot-lon", telemetryItem
.pilotLongitude
* 0.000001);
219 int8_t delay
= telemetryItem
.getDelaySinceLastValue();
221 lua_pushtableinteger(L
, "delay", delay
);
223 lua_pushtablenil(L
, "delay");
226 static void luaPushTelemetryDateTime(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
228 luaPushDateTime(L
, telemetryItem
.datetime
.year
, telemetryItem
.datetime
.month
, telemetryItem
.datetime
.day
,
229 telemetryItem
.datetime
.hour
, telemetryItem
.datetime
.min
, telemetryItem
.datetime
.sec
);
232 static void luaPushCells(lua_State
* L
, TelemetrySensor
& telemetrySensor
, TelemetryItem
& telemetryItem
)
234 if (telemetryItem
.cells
.count
== 0)
235 lua_pushinteger(L
, (int)0); // returns zero if no cells
237 lua_createtable(L
, telemetryItem
.cells
.count
, 0);
238 for (int i
= 0; i
< telemetryItem
.cells
.count
; i
++) {
239 lua_pushnumber(L
, i
+ 1);
240 lua_pushnumber(L
, telemetryItem
.cells
.values
[i
].value
* 0.01f
);
246 void luaGetValueAndPush(lua_State
* L
, int src
)
248 getvalue_t value
= getValue(src
); // ignored for GPS, DATETIME, and CELLS
250 if (src
>= MIXSRC_FIRST_TELEM
&& src
<= MIXSRC_LAST_TELEM
) {
251 div_t qr
= div(src
-MIXSRC_FIRST_TELEM
, 3);
253 if (TELEMETRY_STREAMING() && telemetryItems
[qr
.quot
].isAvailable()) {
254 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[qr
.quot
];
255 switch (telemetrySensor
.unit
) {
257 luaPushLatLon(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
260 luaPushTelemetryDateTime(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
263 lua_pushstring(L
, telemetryItems
[qr
.quot
].text
);
267 luaPushCells(L
, telemetrySensor
, telemetryItems
[qr
.quot
]);
270 // deliberate no break here to properly return `Cels-` and `Cels+`
272 if (telemetrySensor
.prec
> 0)
273 lua_pushnumber(L
, float(value
)/telemetrySensor
.getPrecDivisor());
275 lua_pushinteger(L
, value
);
280 // telemetry not working, return zero for telemetry sources
281 lua_pushinteger(L
, (int)0);
284 else if (src
== MIXSRC_TX_VOLTAGE
) {
285 lua_pushnumber(L
, float(value
) * 0.1f
);
288 lua_pushinteger(L
, value
);
293 Return field data for a given field name
295 bool luaFindFieldByName(const char * name
, LuaField
& field
, unsigned int flags
)
297 // TODO better search method (binary lookup)
298 for (unsigned int n
=0; n
<DIM(luaSingleFields
); ++n
) {
299 if (!strcmp(name
, luaSingleFields
[n
].name
)) {
300 field
.id
= luaSingleFields
[n
].id
;
301 if (flags
& FIND_FIELD_DESC
) {
302 strncpy(field
.desc
, luaSingleFields
[n
].desc
, sizeof(field
.desc
)-1);
303 field
.desc
[sizeof(field
.desc
)-1] = '\0';
306 field
.desc
[0] = '\0';
312 // search in multiples
313 unsigned int len
= strlen(name
);
314 for (unsigned int n
=0; n
<DIM(luaMultipleFields
); ++n
) {
315 const char * fieldName
= luaMultipleFields
[n
].name
;
316 unsigned int fieldLen
= strlen(fieldName
);
317 if (!strncmp(name
, fieldName
, fieldLen
)) {
319 if (len
== fieldLen
+1 && isdigit(name
[fieldLen
])) {
320 index
= name
[fieldLen
] - '1';
322 else if (len
== fieldLen
+2 && isdigit(name
[fieldLen
]) && isdigit(name
[fieldLen
+1])) {
323 index
= 10 * (name
[fieldLen
] - '0') + (name
[fieldLen
+1] - '1');
328 if (index
< luaMultipleFields
[n
].count
) {
329 if(luaMultipleFields
[n
].id
== MIXSRC_FIRST_TELEM
)
330 field
.id
= luaMultipleFields
[n
].id
+ index
*3;
332 field
.id
= luaMultipleFields
[n
].id
+ index
;
333 if (flags
& FIND_FIELD_DESC
) {
334 snprintf(field
.desc
, sizeof(field
.desc
)-1, luaMultipleFields
[n
].desc
, index
+1);
335 field
.desc
[sizeof(field
.desc
)-1] = '\0';
338 field
.desc
[0] = '\0';
345 // search in telemetry
346 field
.desc
[0] = '\0';
347 for (int i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
348 if (isTelemetryFieldAvailable(i
)) {
349 char sensorName
[TELEM_LABEL_LEN
+1];
350 int len
= zchar2str(sensorName
, g_model
.telemetrySensors
[i
].label
, TELEM_LABEL_LEN
);
351 if (!strncmp(sensorName
, name
, len
)) {
352 if (name
[len
] == '\0') {
353 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
;
354 field
.desc
[0] = '\0';
357 else if (name
[len
] == '-' && name
[len
+1] == '\0') {
358 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
+ 1;
359 field
.desc
[0] = '\0';
362 else if (name
[len
] == '+' && name
[len
+1] == '\0') {
363 field
.id
= MIXSRC_FIRST_TELEM
+ 3*i
+ 2;
364 field
.desc
[0] = '\0';
371 return false; // not found
375 @function sportTelemetryPop()
377 Pops a received SPORT packet from the queue. Please note that only packets using a data ID within 0x5000 to 0x50FF
378 (frame ID == 0x10), as well as packets with a frame ID equal 0x32 (regardless of the data ID) will be passed to
379 the LUA telemetry receive queue.
381 @retval nil queue does not contain any (or enough) bytes to form a whole packet
383 @retval multiple returns 4 values:
389 @status current Introduced in 2.2.0
391 static int luaSportTelemetryPop(lua_State
* L
)
393 if (!luaInputTelemetryFifo
) {
394 luaInputTelemetryFifo
= new Fifo
<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE
>();
395 if (!luaInputTelemetryFifo
) {
400 if (luaInputTelemetryFifo
->size() >= sizeof(SportTelemetryPacket
)) {
401 SportTelemetryPacket packet
;
402 for (uint8_t i
=0; i
<sizeof(packet
); i
++) {
403 luaInputTelemetryFifo
->pop(packet
.raw
[i
]);
405 lua_pushnumber(L
, packet
.physicalId
);
406 lua_pushnumber(L
, packet
.primId
);
407 lua_pushnumber(L
, packet
.dataId
);
408 lua_pushunsigned(L
, packet
.value
);
415 #define BIT(x, index) (((x) >> index) & 0x01)
416 uint8_t getDataId(uint8_t physicalId
)
418 uint8_t result
= physicalId
;
419 result
+= (BIT(physicalId
, 0) ^ BIT(physicalId
, 1) ^ BIT(physicalId
, 2)) << 5;
420 result
+= (BIT(physicalId
, 2) ^ BIT(physicalId
, 3) ^ BIT(physicalId
, 4)) << 6;
421 result
+= (BIT(physicalId
, 0) ^ BIT(physicalId
, 2) ^ BIT(physicalId
, 4)) << 7;
426 @function sportTelemetryPush()
428 This functions allows for sending SPORT telemetry data toward the receiver,
429 and more generally, to anything connected SPORT bus on the receiver or transmitter.
431 When called without parameters, it will only return the status of the output buffer without sending anything.
433 @param sensorId physical sensor ID
435 @param frameId frame ID
437 @param dataId data ID
441 @retval boolean data queued in output buffer or not.
443 @status current Introduced in 2.2.0
446 static int luaSportTelemetryPush(lua_State
* L
)
448 if (!IS_FRSKY_SPORT_PROTOCOL()) {
449 lua_pushboolean(L
, false);
453 if (lua_gettop(L
) == 0) {
454 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
458 uint16_t dataId
= luaL_checkunsigned(L
, 3);
460 if (outputTelemetryBuffer
.isAvailable()) {
461 for (uint8_t i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
462 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[i
];
463 if (sensor
.id
== dataId
) {
464 if (sensor
.frskyInstance
.rxIndex
== TELEMETRY_ENDPOINT_SPORT
) {
465 SportTelemetryPacket packet
;
466 packet
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
467 packet
.primId
= luaL_checkunsigned(L
, 2);
468 packet
.dataId
= dataId
;
469 packet
.value
= luaL_checkunsigned(L
, 4);
470 outputTelemetryBuffer
.pushSportPacketWithBytestuffing(packet
);
473 outputTelemetryBuffer
.sport
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
474 outputTelemetryBuffer
.sport
.primId
= luaL_checkunsigned(L
, 2);
475 outputTelemetryBuffer
.sport
.dataId
= dataId
;
476 outputTelemetryBuffer
.sport
.value
= luaL_checkunsigned(L
, 4);
478 outputTelemetryBuffer
.setDestination(sensor
.frskyInstance
.rxIndex
);
479 lua_pushboolean(L
, true);
484 // sensor not found, we send the frame to the SPORT line
486 SportTelemetryPacket packet
;
487 packet
.physicalId
= getDataId(luaL_checkunsigned(L
, 1));
488 packet
.primId
= luaL_checkunsigned(L
, 2);
489 packet
.dataId
= dataId
;
490 packet
.value
= luaL_checkunsigned(L
, 4);
491 outputTelemetryBuffer
.pushSportPacketWithBytestuffing(packet
);
493 uint8_t destination
= (IS_INTERNAL_MODULE_ON() ? INTERNAL_MODULE
: EXTERNAL_MODULE
);
494 outputTelemetryBuffer
.setDestination(isModulePXX2(destination
) ? (destination
<< 2) : TELEMETRY_ENDPOINT_SPORT
);
496 outputTelemetryBuffer
.setDestination(TELEMETRY_ENDPOINT_SPORT
);
498 lua_pushboolean(L
, true);
503 lua_pushboolean(L
, false);
509 @function accessTelemetryPush()
511 This functions allows for sending SPORT / ACCESS telemetry data toward the receiver,
512 and more generally, to anything connected SPORT bus on the receiver or transmitter.
514 When called without parameters, it will only return the status of the output buffer without sending anything.
516 @param module module index (0 = internal, 1 = external)
518 @param rxUid receiver index
520 @param sensorId physical sensor ID
522 @param frameId frame ID
524 @param dataId data ID
528 @retval boolean data queued in output buffer or not.
530 @status current Introduced in 2.3
534 bool getDefaultAccessDestination(uint8_t & destination
)
536 for (uint8_t i
=0; i
<MAX_TELEMETRY_SENSORS
; i
++) {
537 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[i
];
538 if (sensor
.type
== TELEM_TYPE_CUSTOM
) {
539 TelemetryItem sensorItem
= telemetryItems
[i
];
540 if (sensorItem
.isFresh()) {
541 destination
= sensor
.frskyInstance
.rxIndex
;
549 static int luaAccessTelemetryPush(lua_State
* L
)
551 if (lua_gettop(L
) == 0) {
552 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
556 if (outputTelemetryBuffer
.isAvailable()) {
557 int8_t module
= luaL_checkinteger(L
, 1);
558 uint8_t rxUid
= luaL_checkunsigned(L
, 2);
562 if (!getDefaultAccessDestination(destination
)) {
563 lua_pushboolean(L
, false);
568 destination
= (module
<< 2) + rxUid
;
571 outputTelemetryBuffer
.sport
.physicalId
= getDataId(luaL_checkunsigned(L
, 3));
572 outputTelemetryBuffer
.sport
.primId
= luaL_checkunsigned(L
, 4);
573 outputTelemetryBuffer
.sport
.dataId
= luaL_checkunsigned(L
, 5);
574 outputTelemetryBuffer
.sport
.value
= luaL_checkunsigned(L
, 6);
575 outputTelemetryBuffer
.setDestination(destination
);
576 lua_pushboolean(L
, true);
580 lua_pushboolean(L
, false);
585 #if defined(CROSSFIRE)
587 @function crossfireTelemetryPop()
589 Pops a received Crossfire Telemetry packet from the queue.
591 @retval nil queue does not contain any (or enough) bytes to form a whole packet
593 @retval multiple returns 2 values:
595 * packet (table) data bytes
597 @status current Introduced in 2.2.0
599 static int luaCrossfireTelemetryPop(lua_State
* L
)
601 if (!luaInputTelemetryFifo
) {
602 luaInputTelemetryFifo
= new Fifo
<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE
>();
603 if (!luaInputTelemetryFifo
) {
608 uint8_t length
= 0, data
= 0;
609 if (luaInputTelemetryFifo
->probe(length
) && luaInputTelemetryFifo
->size() >= uint32_t(length
)) {
610 // length value includes the length field
611 luaInputTelemetryFifo
->pop(length
);
612 luaInputTelemetryFifo
->pop(data
); // command
613 lua_pushnumber(L
, data
);
615 for (uint8_t i
=1; i
<length
-1; i
++) {
616 luaInputTelemetryFifo
->pop(data
);
617 lua_pushinteger(L
, i
);
618 lua_pushinteger(L
, data
);
628 @function crossfireTelemetryPush()
630 This functions allows for sending telemetry data toward the TBS Crossfire link.
632 When called without parameters, it will only return the status of the output buffer without sending anything.
634 @param command command
636 @param data table of data bytes
638 @retval boolean data queued in output buffer or not.
640 @status current Introduced in 2.2.0
642 static int luaCrossfireTelemetryPush(lua_State
* L
)
644 if (telemetryProtocol
!= PROTOCOL_TELEMETRY_CROSSFIRE
) {
645 lua_pushboolean(L
, false);
649 if (lua_gettop(L
) == 0) {
650 lua_pushboolean(L
, outputTelemetryBuffer
.isAvailable());
652 else if (outputTelemetryBuffer
.isAvailable()) {
653 uint8_t command
= luaL_checkunsigned(L
, 1);
654 luaL_checktype(L
, 2, LUA_TTABLE
);
655 uint8_t length
= luaL_len(L
, 2);
656 outputTelemetryBuffer
.pushByte(MODULE_ADDRESS
);
657 outputTelemetryBuffer
.pushByte(2 + length
); // 1(COMMAND) + data length + 1(CRC)
658 outputTelemetryBuffer
.pushByte(command
); // COMMAND
659 for (int i
=0; i
<length
; i
++) {
660 lua_rawgeti(L
, 2, i
+1);
661 outputTelemetryBuffer
.pushByte(luaL_checkunsigned(L
, -1));
663 outputTelemetryBuffer
.pushByte(crc8(outputTelemetryBuffer
.data
+2, 1 + length
));
664 outputTelemetryBuffer
.setDestination(TELEMETRY_ENDPOINT_SPORT
);
665 lua_pushboolean(L
, true);
668 lua_pushboolean(L
, false);
675 @function getFieldInfo(name)
677 Return detailed information about field (source)
679 The list of valid sources is available:
681 | OpenTX Version | Radio |
682 |----------------|-------|
683 | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) |
684 | 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) |
685 | 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) |
687 @param name (string) name of the field
689 @retval table information about requested field, table elements:
690 * `id` (number) field identifier
691 * `name` (string) field name
692 * `desc` (string) field description
693 * 'unit' (number) unit identifier [Full list](../appendix/units.html)
695 @retval nil the requested field was not found
697 @status current Introduced in 2.0.8, 'unit' field added in 2.2.0
699 static int luaGetFieldInfo(lua_State
* L
)
701 const char * what
= luaL_checkstring(L
, 1);
703 bool found
= luaFindFieldByName(what
, field
, FIND_FIELD_DESC
);
706 lua_pushtableinteger(L
, "id", field
.id
);
707 lua_pushtablestring(L
, "name", what
);
708 lua_pushtablestring(L
, "desc", field
.desc
);
709 if (field
.id
>= MIXSRC_FIRST_TELEM
&& field
.id
<= MIXSRC_LAST_TELEM
) {
710 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[(int)((field
.id
-MIXSRC_FIRST_TELEM
)/3)];
711 lua_pushtableinteger(L
, "unit", telemetrySensor
.unit
);
714 lua_pushtablenil(L
, "unit");
722 @function getValue(source)
724 Returns the value of a source.
726 The list of fixed sources:
728 | OpenTX Version | Radio |
729 |----------------|-------|
730 | 2.0 | [all](http://downloads-20.open-tx.org/firmware/lua_fields.txt) |
731 | 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) |
732 | 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) |
735 In OpenTX 2.1.x the telemetry sources no longer have a predefined name.
736 To get a telemetry value simply use it's sensor name. For example:
737 * Altitude sensor has a name "Alt"
738 * to get the current altitude use the source "Alt"
739 * to get the minimum altitude use the source "Alt-", to get the maximum use "Alt+"
741 @param source can be an identifier (number) (which was obtained by the getFieldInfo())
742 or a name (string) of the source.
744 @retval value current source value (number). Zero is returned for:
745 * non-existing sources
746 * for all telemetry source when the telemetry stream is not received
747 * far all non allowed sensors while FAI MODE is active
749 @retval table GPS position is returned in a table:
750 * `lat` (number) latitude, positive is North
751 * `lon` (number) longitude, positive is East
752 * `pilot-lat` (number) pilot latitude, positive is North
753 * `pilot-lon` (number) pilot longitude, positive is East
755 @retval table GPS date/time, see getDateTime()
757 @retval table Cells are returned in a table
758 (except where no cells were detected in which
759 case the returned value is 0):
760 * table has one item for each detected cell:
761 * key (number) cell number (1 to number of cells)
762 * value (number) current cell voltage
764 @status current Introduced in 2.0.0, changed in 2.1.0, `Cels+` and
765 `Cels-` added in 2.1.9
767 @notice Getting a value by its numerical identifier is faster then by its name.
768 While `Cels` sensor returns current values of all cells in a table, a `Cels+` or
769 `Cels-` will return a single value - the maximum or minimum Cels value.
771 static int luaGetValue(lua_State
* L
)
774 if (lua_isnumber(L
, 1)) {
775 src
= luaL_checkinteger(L
, 1);
778 // convert from field name to its id
779 const char *name
= luaL_checkstring(L
, 1);
781 bool found
= luaFindFieldByName(name
, field
);
786 luaGetValueAndPush(L
, src
);
793 Return the RAS value or nil if no valid hardware found
795 @retval number representing RAS value. Value bellow 0x33 (51 decimal) are all ok, value above 0x33 indicate a hardware antenna issue.
796 This is just a hardware pass/fail measure and does not represent the quality of the radio link
798 @notice RAS was called SWR in the past
800 @status current Introduced in 2.2.0
802 static int luaGetRAS(lua_State
* L
)
804 if (isRasValueValid()) {
805 lua_pushinteger(L
, telemetryData
.swrInternal
.value());
816 Return the internal GPS position or nil if no valid hardware found
818 @retval table representing the current radio position
819 * `lat` (number) internal GPS latitude, positive is North
820 * `lon` (number) internal GPS longitude, positive is East
821 * 'numsat' (number) current number of sats locked in by the GPS sensor
822 * 'fix' (boolean) fix status
823 * 'alt' (number) internal GPS altitude in 0.1m
824 * 'speed' (number) internal GPSspeed in 0.1m/s
825 * 'heading' (number) internal GPS ground course estimation in degrees * 10
826 * 'hdop' (number) internal GPS horizontal dilution of precision
828 @status current Introduced in 2.2.2
830 static int luaGetTxGPS(lua_State
* L
)
832 #if defined(INTERNAL_GPS)
833 lua_createtable(L
, 0, 7);
834 lua_pushtablenumber(L
, "lat", gpsData
.latitude
* 0.000001);
835 lua_pushtablenumber(L
, "lon", gpsData
.longitude
* 0.000001);
836 lua_pushtableinteger(L
, "numsat", gpsData
.numSat
);
837 lua_pushtableinteger(L
, "alt", gpsData
.altitude
);
838 lua_pushtableinteger(L
, "speed", gpsData
.speed
);
839 lua_pushtableinteger(L
, "heading", gpsData
.groundCourse
);
840 lua_pushtableinteger(L
, "hdop", gpsData
.hdop
);
842 lua_pushtableboolean(L
, "fix", true);
844 lua_pushtableboolean(L
, "fix", false);
853 @function getFlightMode(mode)
855 Return flight mode data.
857 @param mode (number) flight mode number to return (0 - 8). If mode parameter
858 is not specified (or contains invalid value), then the current flight mode data is returned.
860 @retval multiple returns 2 values:
861 * (number) (current) flight mode number (0 - 8)
862 * (string) (current) flight mode name
864 @status current Introduced in 2.1.7
866 static int luaGetFlightMode(lua_State
* L
)
868 int mode
= luaL_optinteger(L
, 1, -1);
869 if (mode
< 0 || mode
>= MAX_FLIGHT_MODES
) {
870 mode
= mixerCurrentFlightMode
;
872 lua_pushnumber(L
, mode
);
873 char name
[sizeof(g_model
.flightModeData
[0].name
)+1];
874 zchar2str(name
, g_model
.flightModeData
[mode
].name
, sizeof(g_model
.flightModeData
[0].name
));
875 lua_pushstring(L
, name
);
880 @function playFile(name)
882 Play a file from the SD card
884 @param path (string) full path to wav file (i.e. “/SOUNDS/en/system/tada.wav”)
885 Introduced in 2.1.0: If you use a relative path, the current language is appended
886 to the path (example: for English language: `/SOUNDS/en` is appended)
888 @status current Introduced in 2.0.0, changed in 2.1.0
890 static int luaPlayFile(lua_State
* L
)
892 const char * filename
= luaL_checkstring(L
, 1);
893 if (filename
[0] != '/') {
894 // relative sound file path - use current language dir for absolute path
895 char file
[AUDIO_FILENAME_MAXLEN
+1];
896 char * str
= getAudioPath(file
);
897 strncpy(str
, filename
, AUDIO_FILENAME_MAXLEN
- (str
-file
));
898 file
[AUDIO_FILENAME_MAXLEN
] = 0;
899 PLAY_FILE(file
, 0, 0);
902 PLAY_FILE(filename
, 0, 0);
908 @function playNumber(value, unit [, attributes])
910 Play a numerical value (text to speech)
912 @param value (number) number to play. Value is interpreted as integer.
914 @param unit (number) unit identifier [Full list]((../appendix/units.html))
916 @param attributes (unsigned number) possible values:
917 * `0 or not present` plays integral part of the number (for a number 123 it plays 123)
918 * `PREC1` plays a number with one decimal place (for a number 123 it plays 12.3)
919 * `PREC2` plays a number with two decimal places (for a number 123 it plays 1.23)
921 @status current Introduced in 2.0.0
924 static int luaPlayNumber(lua_State
* L
)
926 int number
= luaL_checkinteger(L
, 1);
927 int unit
= luaL_checkinteger(L
, 2);
928 unsigned int att
= luaL_optunsigned(L
, 3, 0);
929 playNumber(number
, unit
, att
, 0);
934 @function playDuration(duration [, hourFormat])
936 Play a time value (text to speech)
938 @param duration (number) number of seconds to play. Only integral part is used.
940 @param hourFormat (number):
941 * `0 or not present` play format: minutes and seconds.
942 * `!= 0` play format: hours, minutes and seconds.
944 @status current Introduced in 2.1.0
946 static int luaPlayDuration(lua_State
* L
)
948 int duration
= luaL_checkinteger(L
, 1);
949 bool playTime
= (luaL_optinteger(L
, 2, 0) != 0);
950 playDuration(duration
, playTime
? PLAY_TIME
: 0, 0);
955 @function playTone(frequency, duration, pause [, flags [, freqIncr]])
959 @param frequency (number) tone frequency in Hz (from 150 to 15000)
961 @param duration (number) length of the tone in milliseconds
963 @param pause (number) length of the silence after the tone in milliseconds
965 @param flags (number):
966 * `0 or not present` play with normal priority.
967 * `PLAY_BACKGROUND` play in background (built in vario function uses this context)
968 * `PLAY_NOW` play immediately
970 @param freqIncr (number) positive number increases the tone pitch (frequency with time),
971 negative number decreases it. The frequency changes every 10 milliseconds, the change is `freqIncr * 10Hz`.
972 The valid range is from -127 to 127.
974 @status current Introduced in 2.1.0
976 static int luaPlayTone(lua_State
* L
)
978 int frequency
= luaL_checkinteger(L
, 1);
979 int length
= luaL_checkinteger(L
, 2);
980 int pause
= luaL_checkinteger(L
, 3);
981 int flags
= luaL_optinteger(L
, 4, 0);
982 int freqIncr
= luaL_optinteger(L
, 5, 0);
983 audioQueue
.playTone(frequency
, length
, pause
, flags
, freqIncr
);
988 @function playHaptic(duration, pause [, flags])
990 Generate haptic feedback
992 @param duration (number) length of the haptic feedback in milliseconds
994 @param pause (number) length of the silence after haptic feedback in milliseconds
996 @param flags (number):
997 * `0 or not present` play with normal priority
998 * `PLAY_NOW` play immediately
1000 @status current Introduced in 2.2.0
1002 static int luaPlayHaptic(lua_State
* L
)
1005 int length
= luaL_checkinteger(L
, 1);
1006 int pause
= luaL_checkinteger(L
, 2);
1007 int flags
= luaL_optinteger(L
, 3, 0);
1008 haptic
.play(length
, pause
, flags
);
1016 @function killEvents(key)
1018 Stops key state machine. See [Key Events](../key_events.md) for the detailed description.
1020 @param key (number) key to be killed, can also include event type (only the key part is used)
1022 @status current Introduced in 2.0.0
1025 static int luaKillEvents(lua_State
* L
)
1027 uint8_t key
= EVT_KEY_MASK(luaL_checkinteger(L
, 1));
1028 // prevent killing maskable keys (only in telemetry scripts)
1029 // TODO add which tpye of script is running before p_call()
1030 if (IS_MASKABLE(key
)) {
1036 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1040 Returns gray value which can be used in LCD functions
1042 @retval (number) a value that represents amount of *greyness* (from 0 to 15)
1044 @notice Only available on Taranis
1046 @status current Introduced in 2.0.13
1048 static int luaGrey(lua_State
* L
)
1050 int index
= luaL_checkinteger(L
, 1);
1051 lua_pushunsigned(L
, GREY(index
));
1057 @function getGeneralSettings()
1059 Returns (some of) the general radio settings
1061 @retval table with elements:
1062 * `battWarn` (number) radio battery range - warning value
1063 * `battMin` (number) radio battery range - minimum value
1064 * `battMax` (number) radio battery range - maximum value
1065 * `imperial` (number) set to a value different from 0 if the radio is set to the
1067 * `language` (string) radio language (used for menus)
1068 * `voice` (string) voice language (used for speech)
1069 * `gtimer` (number) radio global timer in seconds (does not include current session)
1071 @status current Introduced in 2.0.6, `imperial` added in TODO,
1072 `language` and `voice` added in 2.2.0, gtimer added in 2.2.2.
1075 static int luaGetGeneralSettings(lua_State
* L
)
1078 lua_pushtablenumber(L
, "battWarn", (g_eeGeneral
.vBatWarn
) * 0.1f
);
1079 lua_pushtablenumber(L
, "battMin", (90+g_eeGeneral
.vBatMin
) * 0.1f
);
1080 lua_pushtablenumber(L
, "battMax", (120+g_eeGeneral
.vBatMax
) * 0.1f
);
1081 lua_pushtableinteger(L
, "imperial", g_eeGeneral
.imperial
);
1082 lua_pushtablestring(L
, "language", TRANSLATIONS
);
1083 lua_pushtablestring(L
, "voice", currentLanguagePack
->id
);
1084 lua_pushtableinteger(L
, "gtimer", g_eeGeneral
.globalTimer
);
1089 @function getGlobalTimer()
1091 Returns radio timers
1093 @retval table with elements:
1094 * `gtimer` (number) radio global timer in seconds
1095 * `session` (number) radio session in seconds
1096 * `ttimer` (number) radio throttle timer in seconds
1097 * `tptimer` (number) radio throttle percent timer in seconds
1099 @status current Introduced added in 2.3.0.
1102 static int luaGetGlobalTimer(lua_State
* L
)
1105 lua_pushtableinteger(L
, "total", g_eeGeneral
.globalTimer
+ sessionTimer
);
1106 lua_pushtableinteger(L
, "session", sessionTimer
);
1107 lua_pushtableinteger(L
, "throttle", s_timeCumThr
);
1108 lua_pushtableinteger(L
, "throttlepct", s_timeCum16ThrP
/16);
1113 @function popupInput(title, event, input, min, max)
1115 Raises a pop-up on screen that allows uses input
1117 @param title (string) text to display
1119 @param event (number) the event variable that is passed in from the
1120 Run function (key pressed)
1122 @param input (number) value that can be adjusted by the +/- keys
1124 @param min (number) min value that input can reach (by pressing the - key)
1126 @param max (number) max value that input can reach
1128 @retval number result of the input adjustment
1130 @retval "OK" user pushed ENT key
1132 @retval "CANCEL" user pushed EXIT key
1134 @notice Use only from stand-alone and telemetry scripts.
1136 @status current Introduced in 2.0.0
1139 /* TODO : fix, broken by popups rewrite
1140 static int luaPopupInput(lua_State * L)
1142 event_t event = luaL_checkinteger(L, 2);
1143 warningInputValue = luaL_checkinteger(L, 3);
1144 warningInputValueMin = luaL_checkinteger(L, 4);
1145 warningInputValueMax = luaL_checkinteger(L, 5);
1146 warningText = luaL_checkstring(L, 1);
1147 warningType = WARNING_TYPE_INPUT;
1148 runPopupWarning(event);
1149 if (warningResult) {
1151 lua_pushstring(L, "OK");
1153 else if (!warningText) {
1154 lua_pushstring(L, "CANCEL");
1157 lua_pushinteger(L, warningInputValue);
1165 @function popupWarning(title, event)
1167 Raises a pop-up on screen that shows a warning
1169 @param title (string) text to display
1171 @param event (number) the event variable that is passed in from the
1172 Run function (key pressed)
1174 @retval "CANCEL" user pushed EXIT key
1176 @notice Use only from stand-alone and telemetry scripts.
1178 @status current Introduced in 2.2.0
1180 static int luaPopupWarning(lua_State
* L
)
1182 event_t event
= luaL_checkinteger(L
, 2);
1183 warningText
= luaL_checkstring(L
, 1);
1184 warningType
= WARNING_TYPE_ASTERISK
;
1185 runPopupWarning(event
);
1187 lua_pushstring(L
, "CANCEL");
1197 @function popupConfirmation(title, event)
1199 Raises a pop-up on screen that asks for confirmation
1201 @param title (string) text to display
1203 @param event (number) the event variable that is passed in from the
1204 Run function (key pressed)
1206 @retval "CANCEL" user pushed EXIT key
1208 @notice Use only from stand-alone and telemetry scripts.
1210 @status current Introduced in 2.2.0
1212 static int luaPopupConfirmation(lua_State
* L
)
1214 event_t event
= luaL_checkinteger(L
, 2);
1215 warningText
= luaL_checkstring(L
, 1);
1216 warningType
= WARNING_TYPE_CONFIRM
;
1217 runPopupWarning(event
);
1219 lua_pushstring(L
, warningResult
? "OK" : "CANCEL");
1229 @function defaultStick(channel)
1231 Get stick that is assigned to a channel. See Default Channel Order in General Settings.
1233 @param channel (number) channel number (0 means CH1)
1235 @retval number Stick assigned to this channel (from 0 to 3)
1237 @status current Introduced in 2.0.0
1239 static int luaDefaultStick(lua_State
* L
)
1241 uint8_t channel
= luaL_checkinteger(L
, 1);
1242 lua_pushinteger(L
, channelOrder(channel
+1)-1);
1247 @function setTelemetryValue(id, subID, instance, value [, unit [, precision [, name]]])
1249 @param id Id of the sensor, valid range is from 0 to 0xFFFF
1251 @param subID subID of the sensor, usually 0, valid range is from 0 to 7
1253 @param instance instance of the sensor (SensorID), valid range is from 0 to 0xFF
1255 @param value fed to the sensor
1257 @param unit unit of the sensor [Full list](../appendix/units.html)
1259 @param precision the precision of the sensor
1260 * `0 or not present` no decimal precision.
1261 * `!= 0` value is divided by 10^precision, e.g. value=1000, prec=2 => 10.00.
1263 @param name (string) Name of the sensor if it does not yet exist (4 chars).
1264 * `not present` Name defaults to the Id.
1265 * `present` Sensor takes name of the argument. Argument must have name surrounded by quotes: e.g., "Name"
1267 @retval true, if the sensor was just added. In this case the value is ignored (subsequent call will set the value)
1269 @notice All three parameters `id`, `subID` and `instance` can't be zero at the same time. At least one of them
1270 must be different from zero.
1272 @status current Introduced in 2.2.0
1274 static int luaSetTelemetryValue(lua_State
* L
)
1276 uint16_t id
= luaL_checkunsigned(L
, 1);
1277 uint8_t subId
= luaL_checkunsigned(L
, 2) & 0x7;
1278 uint8_t instance
= luaL_checkunsigned(L
, 3);
1279 int32_t value
= luaL_checkinteger(L
, 4);
1280 uint32_t unit
= luaL_optunsigned(L
, 5, 0);
1281 uint32_t prec
= luaL_optunsigned(L
, 6, 0);
1284 const char* name
= luaL_optstring(L
, 7, NULL
);
1285 if (name
!= NULL
&& strlen(name
) > 0) {
1286 str2zchar(zname
, name
, 4);
1289 zname
[0] = hex2zchar((id
& 0xf000) >> 12);
1290 zname
[1] = hex2zchar((id
& 0x0f00) >> 8);
1291 zname
[2] = hex2zchar((id
& 0x00f0) >> 4);
1292 zname
[3] = hex2zchar((id
& 0x000f) >> 0);
1294 if (id
| subId
| instance
) {
1295 int index
= setTelemetryValue(PROTOCOL_TELEMETRY_LUA
, id
, subId
, instance
, value
, unit
, prec
);
1297 TelemetrySensor
&telemetrySensor
= g_model
.telemetrySensors
[index
];
1298 telemetrySensor
.id
= id
;
1299 telemetrySensor
.subId
= subId
;
1300 telemetrySensor
.instance
= instance
;
1301 telemetrySensor
.init(zname
, unit
, prec
);
1302 lua_pushboolean(L
, true);
1305 lua_pushboolean(L
, false);
1309 lua_pushboolean(L
, false);
1314 @function defaultChannel(stick)
1316 Get channel assigned to stick. See Default Channel Order in General Settings
1318 @param stick (number) stick number (from 0 to 3)
1320 @retval number channel assigned to this stick (from 0 to 3)
1322 @retval nil stick not found
1324 @status current Introduced in 2.0.0
1326 static int luaDefaultChannel(lua_State
* L
)
1328 uint8_t stick
= luaL_checkinteger(L
, 1);
1329 for (int i
=1; i
<=4; i
++) {
1330 int tmp
= channelOrder(i
) - 1;
1332 lua_pushinteger(L
, i
-1);
1343 Get RSSI value as well as low and critical RSSI alarm levels (in dB)
1345 @retval rssi RSSI value (0 if no link)
1347 @retval alarm_low Configured low RSSI alarm level
1349 @retval alarm_crit Configured critical RSSI alarm level
1351 @status current Introduced in 2.2.0
1353 static int luaGetRSSI(lua_State
* L
)
1355 lua_pushunsigned(L
, min((uint8_t)99, TELEMETRY_RSSI()));
1356 lua_pushunsigned(L
, g_model
.rssiAlarms
.getWarningRssi());
1357 lua_pushunsigned(L
, g_model
.rssiAlarms
.getCriticalRssi());
1362 @function chdir(directory)
1364 Change the working directory
1366 @param directory (string) New working directory
1368 @status current Introduced in 2.3.0
1372 static int luaChdir(lua_State
* L
)
1374 const char * directory
= luaL_optstring(L
, 1, nullptr);
1380 @function loadScript(file [, mode], [,env])
1382 Load a Lua script file. This is similar to Lua's own [loadfile()](https://www.lua.org/manual/5.2/manual.html#pdf-loadfile)
1383 API method, but it uses OpenTx's optional pre-compilation feature to save memory and time during load.
1385 Return values are same as from Lua API loadfile() method: If the script was loaded w/out errors
1386 then the loaded script (or "chunk") is returned as a function. Otherwise, returns nil plus the error message.
1388 @param file (string) Full path and file name of script. The file extension is optional and ignored (see `mode` param to control
1389 which extension will be used). However, if an extension is specified, it should be ".lua" (or ".luac"), otherwise it is treated
1390 as part of the file name and the .lua/.luac will be appended to that.
1392 @param mode (string) (optional) Controls whether to force loading the text (.lua) or pre-compiled binary (.luac)
1393 version of the script. By default OTx will load the newest version and compile a new binary if necessary (overwriting any
1394 existing .luac version of the same script, and stripping some debug info like line numbers).
1395 You can use `mode` to control the loading behavior more specifically. Possible values are:
1398 * `T` (default on simulator) prefer text but load binary if that is the only version available.
1399 * `bt` (default on radio) either binary or text, whichever is newer (binary preferred when timestamps are equal).
1400 * Add `x` to avoid automatic compilation of source file to .luac version.
1401 Eg: "tx", "bx", or "btx".
1402 * Add `c` to force compilation of source file to .luac version (even if existing version is newer than source file).
1403 Eg: "tc" or "btc" (forces "t", overrides "x").
1404 * Add `d` to keep extra debug info in the compiled binary.
1405 Eg: "td", "btd", or "tcd" (no effect with just "b" or with "x").
1408 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).
1409 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()).
1411 @param env (integer) See documentation for Lua function loadfile().
1413 @retval function The loaded script, or `nil` if there was an error (e.g. file not found or syntax error).
1415 @retval string Error message(s), if any. Blank if no error occurred.
1417 @status current Introduced in 2.2.0
1422 fun, err = loadScript("/SCRIPTS/FUNCTIONS/print.lua")
1423 if (fun ~= nil) then
1424 fun("Hello from loadScript()")
1431 static int luaLoadScript(lua_State
* L
)
1433 // this function is replicated pretty much verbatim from luaB_loadfile() and load_aux() in lbaselib.c
1434 const char *fname
= luaL_optstring(L
, 1, NULL
);
1435 const char *mode
= luaL_optstring(L
, 2, NULL
);
1436 int env
= (!lua_isnone(L
, 3) ? 3 : 0); // 'env' index or 0 if no 'env'
1438 if (fname
!= NULL
&& luaLoadScriptFileToState(L
, fname
, mode
) == SCRIPT_OK
) {
1439 if (env
!= 0) { // 'env' parameter?
1440 lua_pushvalue(L
, env
); // environment for loaded function
1441 if (!lua_setupvalue(L
, -2, 1)) // set it as 1st upvalue
1442 lua_pop(L
, 1); // remove 'env' if not used by previous call
1447 // error (message should be on top of the stack)
1448 if (!lua_isstring(L
, -1)) {
1449 // probably didn't find a file or had some other error before luaL_loadfile() was run
1450 lua_pushfstring(L
, "loadScript(\"%s\", \"%s\") error: File not found", (fname
!= NULL
? fname
: "nul"), (mode
!= NULL
? mode
: "bt"));
1453 lua_insert(L
, -2); // move nil before error message
1454 return 2; // return nil plus error message
1459 @function getUsage()
1461 Get percent of already used Lua instructions in current script execution cycle.
1463 @retval usage (number) a value from 0 to 100 (percent)
1465 @status current Introduced in 2.2.1
1467 static int luaGetUsage(lua_State
* L
)
1469 lua_pushinteger(L
, instructionsPercent
);
1474 @function resetGlobalTimer([type])
1476 Resets the radio global timer to 0.
1478 @param (optional) : if set to 'all', throttle ,throttle percent and session timers are reset too
1479 if set to 'session', radio session timer is reset too
1480 if set to 'ttimer', radio throttle timer is reset too
1481 if set to 'tptimer', radio throttle percent timer is reset too
1483 @status current Introduced in 2.2.2, param added in 2.3
1485 static int luaResetGlobalTimer(lua_State
* L
)
1488 const char * option
= luaL_optlstring(L
, 1, "total", &length
);
1489 if (!strcmp(option
, "all")) {
1490 g_eeGeneral
.globalTimer
= 0;
1493 s_timeCum16ThrP
= 0;
1495 else if (!strcmp(option
, "total")) {
1496 g_eeGeneral
.globalTimer
= 0;
1499 else if (!strcmp(option
, "session")) {
1502 else if (!strcmp(option
, "throttle")) {
1505 else if (!strcmp(option
, "throttlepct")) {
1506 s_timeCum16ThrP
= 0;
1508 storageDirty(EE_GENERAL
);
1513 @function multiBuffer(address[,value])
1515 This function reads/writes the Multi protocol buffer to interact with a protocol².
1517 @param address to read/write in the buffer
1518 @param (optional): value to write in the buffer
1520 @retval buffer value (number)
1522 @status current Introduced in 2.3.2
1524 #if defined(MULTIMODULE)
1525 uint8_t * Multi_Buffer
= nullptr;
1527 static int luaMultiBuffer(lua_State
* L
)
1529 uint8_t address
= luaL_checkunsigned(L
, 1);
1531 Multi_Buffer
= (uint8_t *) malloc(MULTI_BUFFER_SIZE
);
1533 if (!Multi_Buffer
|| address
>= MULTI_BUFFER_SIZE
) {
1534 lua_pushinteger(L
, 0);
1537 uint16_t value
= luaL_optunsigned(L
, 2, 0x100);
1538 if (value
< 0x100) {
1539 Multi_Buffer
[address
] = value
;
1541 lua_pushinteger(L
, Multi_Buffer
[address
]);
1547 @function serialWrite(str)
1548 @param str (string) String to be written to the serial port.
1550 Writes a string to the serial port. The string is allowed to contain any character, including 0.
1552 @status current Introduced in TODO
1554 static int luaSerialWrite(lua_State
* L
)
1556 const char * str
= luaL_checkstring(L
, 1);
1557 size_t len
= lua_rawlen(L
, 1);
1559 if (!str
|| len
< 1)
1563 #if defined(USB_SERIAL)
1564 if (getSelectedUsbMode() == USB_SERIAL_MODE
) {
1565 size_t wr_len
= len
;
1566 const char* p
= str
;
1567 while(wr_len
--) usbSerialPutc(*p
++);
1570 #if defined(AUX_SERIAL)
1571 if (auxSerialMode
== UART_MODE_LUA
) {
1572 size_t wr_len
= len
;
1573 const char* p
= str
;
1574 while(wr_len
--) auxSerialPutc(*p
++);
1578 debugPrintf("luaSerialWrite: %.*s",len
,str
);
1584 const luaL_Reg opentxLib
[] = {
1585 { "getTime", luaGetTime
},
1586 { "getDateTime", luaGetDateTime
},
1587 #if defined(RTCLOCK)
1588 { "getRtcTime", luaGetRtcTime
},
1590 { "getVersion", luaGetVersion
},
1591 { "getGeneralSettings", luaGetGeneralSettings
},
1592 { "getGlobalTimer", luaGetGlobalTimer
},
1593 { "getValue", luaGetValue
},
1594 { "getRAS", luaGetRAS
},
1595 { "getTxGPS", luaGetTxGPS
},
1596 { "getFieldInfo", luaGetFieldInfo
},
1597 { "getFlightMode", luaGetFlightMode
},
1598 { "playFile", luaPlayFile
},
1599 { "playNumber", luaPlayNumber
},
1600 { "playDuration", luaPlayDuration
},
1601 { "playTone", luaPlayTone
},
1602 { "playHaptic", luaPlayHaptic
},
1603 // { "popupInput", luaPopupInput },
1604 { "popupWarning", luaPopupWarning
},
1605 { "popupConfirmation", luaPopupConfirmation
},
1606 { "defaultStick", luaDefaultStick
},
1607 { "defaultChannel", luaDefaultChannel
},
1608 { "getRSSI", luaGetRSSI
},
1609 { "killEvents", luaKillEvents
},
1610 { "chdir", luaChdir
},
1611 { "loadScript", luaLoadScript
},
1612 { "getUsage", luaGetUsage
},
1613 { "resetGlobalTimer", luaResetGlobalTimer
},
1614 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1615 { "GREY", luaGrey
},
1618 { "accessTelemetryPush", luaAccessTelemetryPush
},
1620 { "sportTelemetryPop", luaSportTelemetryPop
},
1621 { "sportTelemetryPush", luaSportTelemetryPush
},
1622 { "setTelemetryValue", luaSetTelemetryValue
},
1623 #if defined(CROSSFIRE)
1624 { "crossfireTelemetryPop", luaCrossfireTelemetryPop
},
1625 { "crossfireTelemetryPush", luaCrossfireTelemetryPush
},
1627 #if defined(MULTIMODULE)
1628 { "multiBuffer", luaMultiBuffer
},
1630 { "serialWrite", luaSerialWrite
},
1631 { nullptr, nullptr } /* sentinel */
1634 const luaR_value_entry opentxConstants
[] = {
1635 { "FULLSCALE", RESX
},
1636 { "XXLSIZE", XXLSIZE
},
1637 { "DBLSIZE", DBLSIZE
},
1638 { "MIDSIZE", MIDSIZE
},
1639 { "SMLSIZE", SMLSIZE
},
1640 { "INVERS", INVERS
},
1645 { "CENTER", CENTERED
},
1648 { "VALUE", INPUT_TYPE_VALUE
},
1649 { "SOURCE", INPUT_TYPE_SOURCE
},
1650 { "REPLACE", MLTPX_REP
},
1651 { "MIXSRC_FIRST_INPUT", MIXSRC_FIRST_INPUT
},
1652 { "MIXSRC_Rud", MIXSRC_Rud
},
1653 { "MIXSRC_Ele", MIXSRC_Ele
},
1654 { "MIXSRC_Thr", MIXSRC_Thr
},
1655 { "MIXSRC_Ail", MIXSRC_Ail
},
1656 { "MIXSRC_SA", MIXSRC_SA
},
1657 { "MIXSRC_SB", MIXSRC_SB
},
1658 { "MIXSRC_SC", MIXSRC_SC
},
1659 { "MIXSRC_SD", MIXSRC_SD
},
1660 #if !defined(PCBX7) && !defined(PCBXLITE) && !defined(PCBX9LITE)
1661 { "MIXSRC_SE", MIXSRC_SE
},
1662 { "MIXSRC_SG", MIXSRC_SG
},
1664 #if !defined(PCBXLITE) && !defined(PCBX9LITE)
1665 { "MIXSRC_SF", MIXSRC_SF
},
1666 { "MIXSRC_SH", MIXSRC_SH
},
1668 { "MIXSRC_CH1", MIXSRC_CH1
},
1669 { "SWSRC_LAST", SWSRC_LAST_LOGICAL_SWITCH
},
1670 { "MAX_SENSORS", MAX_TELEMETRY_SENSORS
},
1671 #if defined(COLORLCD)
1672 { "SHADOWED", SHADOWED
},
1673 { "COLOR", ZoneOption::Color
},
1674 { "BOOL", ZoneOption::Bool
},
1675 { "STRING", ZoneOption::String
},
1676 { "CUSTOM_COLOR", CUSTOM_COLOR
},
1677 { "TEXT_COLOR", TEXT_COLOR
},
1678 { "TEXT_BGCOLOR", TEXT_BGCOLOR
},
1679 { "TEXT_INVERTED_COLOR", TEXT_INVERTED_COLOR
},
1680 { "TEXT_INVERTED_BGCOLOR", TEXT_INVERTED_BGCOLOR
},
1681 { "LINE_COLOR", LINE_COLOR
},
1682 { "SCROLLBOX_COLOR", SCROLLBOX_COLOR
},
1683 { "MENU_TITLE_BGCOLOR", MENU_TITLE_BGCOLOR
},
1684 { "MENU_TITLE_COLOR", MENU_TITLE_COLOR
},
1685 { "MENU_TITLE_DISABLE_COLOR", MENU_TITLE_DISABLE_COLOR
},
1686 { "ALARM_COLOR", ALARM_COLOR
},
1687 { "WARNING_COLOR", WARNING_COLOR
},
1688 { "TEXT_DISABLE_COLOR", TEXT_DISABLE_COLOR
},
1689 { "HEADER_COLOR", HEADER_COLOR
},
1690 { "CURVE_AXIS_COLOR", CURVE_AXIS_COLOR
},
1691 { "CURVE_COLOR", CURVE_COLOR
},
1692 { "CURVE_CURSOR_COLOR", CURVE_CURSOR_COLOR
},
1693 { "TITLE_BGCOLOR", TITLE_BGCOLOR
},
1694 { "TRIM_BGCOLOR", TRIM_BGCOLOR
},
1695 { "TRIM_SHADOW_COLOR", TRIM_SHADOW_COLOR
},
1696 { "MAINVIEW_PANES_COLOR", MAINVIEW_PANES_COLOR
},
1697 { "MAINVIEW_GRAPHICS_COLOR", MAINVIEW_GRAPHICS_COLOR
},
1698 { "HEADER_BGCOLOR", HEADER_BGCOLOR
},
1699 { "HEADER_ICON_BGCOLOR", HEADER_ICON_BGCOLOR
},
1700 { "HEADER_CURRENT_BGCOLOR", HEADER_CURRENT_BGCOLOR
},
1701 { "OVERLAY_COLOR", OVERLAY_COLOR
},
1702 { "MENU_HEADER_HEIGHT", MENU_HEADER_HEIGHT
},
1703 { "WHITE", (double)WHITE
},
1704 { "GREY", (double)GREY
},
1705 { "DARKGREY", (double)DARKGREY
},
1706 { "BLACK", (double)BLACK
},
1707 { "YELLOW", (double)YELLOW
},
1708 { "BLUE", (double)BLUE
},
1709 { "LIGHTGREY", (double)LIGHTGREY
},
1710 { "RED", (double)RED
},
1711 { "DARKRED", (double)DARKRED
},
1713 { "FIXEDWIDTH", FIXEDWIDTH
},
1717 #if defined(ROTARY_ENCODER_NAVIGATION)
1718 { "EVT_VIRTUAL_PREV", EVT_ROTARY_LEFT
},
1719 { "EVT_VIRTUAL_NEXT", EVT_ROTARY_RIGHT
},
1720 { "EVT_VIRTUAL_DEC", EVT_ROTARY_LEFT
},
1721 { "EVT_VIRTUAL_INC", EVT_ROTARY_RIGHT
},
1722 #elif defined(PCBX9D) || defined(PCBX9DP) // key reverted between field nav and value change
1723 { "EVT_VIRTUAL_PREV", EVT_KEY_FIRST(KEY_PLUS
) },
1724 { "EVT_VIRTUAL_PREV_REPT", EVT_KEY_REPT(KEY_PLUS
) },
1725 { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_MINUS
) },
1726 { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_MINUS
) },
1727 { "EVT_VIRTUAL_DEC", EVT_KEY_FIRST(KEY_MINUS
) },
1728 { "EVT_VIRTUAL_DEC_REPT", EVT_KEY_REPT(KEY_MINUS
) },
1729 { "EVT_VIRTUAL_INC", EVT_KEY_FIRST(KEY_PLUS
) },
1730 { "EVT_VIRTUAL_INC_REPT", EVT_KEY_REPT(KEY_PLUS
) },
1732 { "EVT_VIRTUAL_PREV", EVT_KEY_FIRST(KEY_UP
) },
1733 { "EVT_VIRTUAL_PREV_REPT", EVT_KEY_REPT(KEY_UP
) },
1734 { "EVT_VIRTUAL_NEXT", EVT_KEY_FIRST(KEY_DOWN
) },
1735 { "EVT_VIRTUAL_NEXT_REPT", EVT_KEY_REPT(KEY_DOWN
) },
1736 { "EVT_VIRTUAL_DEC", EVT_KEY_FIRST(KEY_DOWN
) },
1737 { "EVT_VIRTUAL_DEC_REPT", EVT_KEY_REPT(KEY_DOWN
) },
1738 { "EVT_VIRTUAL_INC", EVT_KEY_FIRST(KEY_UP
) },
1739 { "EVT_VIRTUAL_INC_REPT", EVT_KEY_REPT(KEY_UP
) },
1742 #if defined(NAVIGATION_9X) || defined(NAVIGATION_XLITE)
1743 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_LEFT
) },
1744 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_LEFT
) },
1745 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_RIGHT
) },
1746 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_RIGHT
) },
1747 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1748 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1749 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1750 #elif defined(NAVIGATION_X7) || defined(NAVIGATION_X9D)
1751 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_PAGE
) },
1752 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PAGE
) },
1753 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MENU
) },
1754 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MENU
) },
1755 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1756 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1757 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1758 #elif defined(NAVIGATION_HORUS)
1759 #if defined(KEYS_GPIO_REG_PGUP)
1760 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_BREAK(KEY_PGUP
) },
1761 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PGDN
) },
1763 { "EVT_VIRTUAL_PREV_PAGE", EVT_KEY_LONG(KEY_PGDN
) },
1764 { "EVT_VIRTUAL_NEXT_PAGE", EVT_KEY_BREAK(KEY_PGDN
) },
1766 { "EVT_VIRTUAL_MENU", EVT_KEY_BREAK(KEY_MODEL
) },
1767 { "EVT_VIRTUAL_MENU_LONG", EVT_KEY_LONG(KEY_MODEL
) },
1768 { "EVT_VIRTUAL_ENTER", EVT_KEY_BREAK(KEY_ENTER
) },
1769 { "EVT_VIRTUAL_ENTER_LONG", EVT_KEY_LONG(KEY_ENTER
) },
1770 { "EVT_VIRTUAL_EXIT", EVT_KEY_BREAK(KEY_EXIT
) },
1773 #if defined(KEYS_GPIO_REG_EXIT)
1774 { "EVT_EXIT_BREAK", EVT_KEY_BREAK(KEY_EXIT
) },
1777 #if defined(KEYS_GPIO_REG_ENTER)
1778 KEY_EVENTS(ENTER
, KEY_ENTER
),
1781 #if defined(KEYS_GPIO_REG_MENU)
1782 KEY_EVENTS(MENU
, KEY_MENU
),
1785 #if defined(KEYS_GPIO_REG_RIGHT) && defined(NAVIGATION_HORUS)
1786 KEY_EVENTS(TELEM
, KEY_TELEM
),
1787 #elif defined(KEYS_GPIO_REG_RIGHT)
1788 KEY_EVENTS(RIGHT
, KEY_RIGHT
),
1791 #if defined(KEYS_GPIO_REG_UP) && defined(NAVIGATION_HORUS)
1792 KEY_EVENTS(MODEL
, KEY_MODEL
),
1793 #elif defined(KEYS_GPIO_REG_UP)
1794 KEY_EVENTS(UP
, KEY_UP
),
1797 #if defined(KEYS_GPIO_REG_LEFT) && defined(NAVIGATION_HORUS)
1798 KEY_EVENTS(SYS
, KEY_RADIO
),
1799 #elif defined(KEYS_GPIO_REG_LEFT)
1800 KEY_EVENTS(LEFT
, KEY_LEFT
),
1803 #if defined(KEYS_GPIO_REG_DOWN) && defined(NAVIGATION_HORUS)
1804 { "EVT_RTN_FIRST", EVT_KEY_BREAK(KEY_EXIT
) },
1806 KEY_EVENTS(DOWN
, KEY_DOWN
),
1809 #if defined(KEYS_GPIO_REG_PGUP)
1810 KEY_EVENTS(PAGEUP
, KEY_PGUP
),
1813 #if defined(KEYS_GPIO_REG_PGDN)
1814 KEY_EVENTS(PAGEDN
, KEY_PGDN
),
1817 #if defined(KEYS_GPIO_REG_PAGE)
1818 KEY_EVENTS(PAGE
, KEY_PAGE
),
1821 #if defined(KEYS_GPIO_REG_SHIFT)
1822 KEY_EVENTS(SHIFT
, KEY_SHIFT
),
1825 #if defined(KEYS_GPIO_REG_PLUS)
1826 KEY_EVENTS(PLUS
, KEY_PLUS
),
1829 #if defined(KEYS_GPIO_REG_MINUS)
1830 KEY_EVENTS(MINUS
, KEY_MINUS
),
1833 #if defined(ROTARY_ENCODER_NAVIGATION)
1834 KEY_EVENTS(ROT
, KEY_ENTER
),
1835 { "EVT_ROT_LEFT", EVT_ROTARY_LEFT
},
1836 { "EVT_ROT_RIGHT", EVT_ROTARY_RIGHT
},
1839 #if LCD_DEPTH > 1 && !defined(COLORLCD)
1840 { "FILL_WHITE", FILL_WHITE
},
1841 { "GREY_DEFAULT", GREY_DEFAULT
},
1851 { "DOTTED", DOTTED
},
1854 { "PLAY_NOW", PLAY_NOW
},
1855 { "PLAY_BACKGROUND", PLAY_BACKGROUND
},
1856 { "TIMEHOUR", TIMEHOUR
},
1858 #if defined(PCBHORUS)
1859 // Adding the unit consts for the set Telemetry function adds about 1k of flash usage
1860 {"UNIT_RAW", UNIT_RAW
},
1861 {"UNIT_VOLTS", UNIT_VOLTS
},
1862 {"UNIT_AMPS", UNIT_AMPS
},
1863 {"UNIT_MILLIAMPS", UNIT_MILLIAMPS
},
1864 {"UNIT_KTS", UNIT_KTS
},
1865 {"UNIT_METERS_PER_SECOND", UNIT_METERS_PER_SECOND
},
1866 {"UNIT_FEET_PER_SECOND", UNIT_FEET_PER_SECOND
},
1867 {"UNIT_KMH", UNIT_KMH
},
1868 {"UNIT_MPH", UNIT_MPH
},
1869 {"UNIT_METERS", UNIT_METERS
},
1870 {"UNIT_FEET", UNIT_FEET
},
1871 {"UNIT_CELSIUS", UNIT_CELSIUS
},
1872 {"UNIT_FAHRENHEIT", UNIT_FAHRENHEIT
},
1873 {"UNIT_PERCENT", UNIT_PERCENT
},
1874 {"UNIT_MAH", UNIT_MAH
},
1875 {"UNIT_WATTS", UNIT_WATTS
},
1876 {"UNIT_MILLIWATTS", UNIT_MILLIWATTS
},
1877 {"UNIT_DB", UNIT_DB
},
1878 {"UNIT_RPMS", UNIT_RPMS
},
1879 {"UNIT_G", UNIT_G
},
1880 {"UNIT_DEGREE", UNIT_DEGREE
},
1881 {"UNIT_RADIANS", UNIT_RADIANS
},
1882 {"UNIT_MILLILITERS", UNIT_MILLILITERS
},
1883 {"UNIT_FLOZ", UNIT_FLOZ
},
1884 {"UNIT_MILLILITERS_PER_MINUTE", UNIT_MILLILITERS_PER_MINUTE
},
1885 {"UNIT_HOURS", UNIT_HOURS
},
1886 {"UNIT_MINUTES", UNIT_MINUTES
},
1887 {"UNIT_SECONDS", UNIT_SECONDS
},
1888 {"UNIT_CELLS", UNIT_CELLS
},
1889 {"UNIT_DATETIME", UNIT_DATETIME
},
1890 {"UNIT_GPS", UNIT_GPS
},
1891 {"UNIT_BITFIELD", UNIT_BITFIELD
},
1892 {"UNIT_TEXT", UNIT_TEXT
},
1894 { nullptr, 0 } /* sentinel */