Merge branch 'master' into change-to-sending-expresslrs_RFrates_e-in-sync-packet
[ExpressLRS.git] / src / lib / LUA / rx_devLUA.cpp
blobc6e0ee4b45788c4b550dc5df41ffd3fda18e7b2a
1 #ifdef TARGET_RX
3 #include "rxtx_devLua.h"
4 #include "helpers.h"
5 #include "devServoOutput.h"
6 #include "deferred.h"
8 #define RX_HAS_SERIAL1 (GPIO_PIN_SERIAL1_TX != UNDEF_PIN || OPT_HAS_SERVO_OUTPUT)
10 extern void reconfigureSerial();
11 #if defined(PLATFORM_ESP32)
12 extern void reconfigureSerial1();
13 #endif
14 extern bool BindingModeRequest;
16 static char modelString[] = "000";
17 #if defined(GPIO_PIN_PWM_OUTPUTS)
18 static char pwmModes[] = "50Hz;60Hz;100Hz;160Hz;333Hz;400Hz;10kHzDuty;On/Off;DShot;Serial RX;Serial TX;I2C SCL;I2C SDA;Serial2 RX;Serial2 TX";
19 #endif
21 static struct luaItem_selection luaSerialProtocol = {
22 {"Protocol", CRSF_TEXT_SELECTION},
23 0, // value
24 "CRSF;Inverted CRSF;SBUS;Inverted SBUS;SUMD;DJI RS Pro;HoTT Telemetry;MAVLink;DisplayPort",
25 STR_EMPTYSPACE
28 #if defined(PLATFORM_ESP32)
29 static struct luaItem_selection luaSerial1Protocol = {
30 {"Protocol2", CRSF_TEXT_SELECTION},
31 0, // value
32 "Off;CRSF;Inverted CRSF;SBUS;Inverted SBUS;SUMD;DJI RS Pro;HoTT Telemetry;Tramp;SmartAudio;DisplayPort",
33 STR_EMPTYSPACE
35 #endif
37 static struct luaItem_selection luaSBUSFailsafeMode = {
38 {"SBUS failsafe", CRSF_TEXT_SELECTION},
39 0, // value
40 "No Pulses;Last Pos",
41 STR_EMPTYSPACE
44 static struct luaItem_int8 luaTargetSysId = {
45 {"Target SysID", CRSF_UINT8},
48 (uint8_t)1, // value - default to 1
49 (uint8_t)1, // min
50 (uint8_t)255, // max
53 STR_EMPTYSPACE
55 static struct luaItem_int8 luaSourceSysId = {
56 {"Source SysID", CRSF_UINT8},
59 (uint8_t)255, // value - default to 255
60 (uint8_t)1, // min
61 (uint8_t)255, // max
64 STR_EMPTYSPACE
67 #if defined(POWER_OUTPUT_VALUES)
68 static struct luaItem_selection luaTlmPower = {
69 {"Tlm Power", CRSF_TEXT_SELECTION},
70 0, // value
71 strPowerLevels,
72 "mW"
74 #endif
76 #if defined(GPIO_PIN_ANT_CTRL)
77 static struct luaItem_selection luaAntennaMode = {
78 {"Ant. Mode", CRSF_TEXT_SELECTION},
79 0, // value
80 "Antenna A;Antenna B;Diversity",
81 STR_EMPTYSPACE
83 #endif
85 // Gemini Mode
86 #if defined(GPIO_PIN_NSS_2)
87 static struct luaItem_selection luaDiversityMode = {
88 {"Rx Mode", CRSF_TEXT_SELECTION},
89 0, // value
90 "Diversity;Gemini",
91 STR_EMPTYSPACE
93 #endif
95 static struct luaItem_folder luaTeamraceFolder = {
96 {"Team Race", CRSF_FOLDER},
99 static struct luaItem_selection luaTeamraceChannel = {
100 {"Channel", CRSF_TEXT_SELECTION},
101 0, // value
102 "AUX2;AUX3;AUX4;AUX5;AUX6;AUX7;AUX8;AUX9;AUX10;AUX11;AUX12",
103 STR_EMPTYSPACE
106 static struct luaItem_selection luaTeamracePosition = {
107 {"Position", CRSF_TEXT_SELECTION},
108 0, // value
109 "Disabled;1/Low;2;3;Mid;4;5;6/High",
110 STR_EMPTYSPACE
113 //----------------------------Info-----------------------------------
115 static struct luaItem_string luaModelNumber = {
116 {"Model Id", CRSF_INFO},
117 modelString
120 static struct luaItem_string luaELRSversion = {
121 {version, CRSF_INFO},
122 commit
125 //----------------------------Info-----------------------------------
127 //---------------------------- WiFi -----------------------------
130 //---------------------------- WiFi -----------------------------
132 //---------------------------- Output Mapping -----------------------------
134 #if defined(GPIO_PIN_PWM_OUTPUTS)
135 static struct luaItem_folder luaMappingFolder = {
136 {"Output Mapping", CRSF_FOLDER},
139 static struct luaItem_int8 luaMappingChannelOut = {
140 {"Output Ch", CRSF_UINT8},
143 (uint8_t)5, // value - start on AUX1, value is 1-16, not zero-based
144 1, // min
145 PWM_MAX_CHANNELS, // max
148 STR_EMPTYSPACE
151 static struct luaItem_int8 luaMappingChannelIn = {
152 {"Input Ch", CRSF_UINT8},
155 0, // value
156 1, // min
157 CRSF_NUM_CHANNELS, // max
160 STR_EMPTYSPACE
163 static struct luaItem_selection luaMappingOutputMode = {
164 {"Output Mode", CRSF_TEXT_SELECTION},
165 0, // value
166 pwmModes,
167 STR_EMPTYSPACE
170 static struct luaItem_selection luaMappingInverted = {
171 {"Invert", CRSF_TEXT_SELECTION},
172 0, // value
173 "Off;On",
174 STR_EMPTYSPACE
177 static struct luaItem_command luaSetFailsafe = {
178 {"Set Failsafe Pos", CRSF_COMMAND},
179 lcsIdle, // step
180 STR_EMPTYSPACE
183 #endif // GPIO_PIN_PWM_OUTPUTS
185 //---------------------------- Output Mapping -----------------------------
187 static struct luaItem_selection luaBindStorage = {
188 {"Bind Storage", CRSF_TEXT_SELECTION},
189 0, // value
190 "Persistent;Volatile;Returnable",
191 STR_EMPTYSPACE
194 static struct luaItem_command luaBindMode = {
195 {STR_EMPTYSPACE, CRSF_COMMAND},
196 lcsIdle, // step
197 STR_EMPTYSPACE
200 #if defined(GPIO_PIN_PWM_OUTPUTS)
201 static void luaparamMappingChannelOut(struct luaPropertiesCommon *item, uint8_t arg)
203 bool sclAssigned = false;
204 bool sdaAssigned = false;
205 #if defined(PLATFORM_ESP32)
206 bool serial1rxAssigned = false;
207 bool serial1txAssigned = false;
208 #endif
210 const char *no1Option = ";";
211 const char *no2Options = ";;";
212 const char *dshot = ";DShot";
213 const char *serial_RX = ";Serial RX";
214 const char *serial_TX = ";Serial TX";
215 const char *i2c_SCL = ";I2C SCL;";
216 const char *i2c_SDA = ";;I2C SDA";
217 const char *i2c_BOTH = ";I2C SCL;I2C SDA";
218 #if defined(PLATFORM_ESP32)
219 const char *serial1_RX = ";Serial2 RX;";
220 const char *serial1_TX = ";;Serial2 TX";
221 const char *serial1_BOTH = ";Serial2 RX;Serial2 TX";
222 #endif
224 const char *pModeString;
227 // find out if use once only modes have already been assigned
228 for (uint8_t ch = 0; ch < GPIO_PIN_PWM_OUTPUTS_COUNT; ch++)
230 if (ch == (arg -1))
231 continue;
233 eServoOutputMode mode = (eServoOutputMode)config.GetPwmChannel(ch)->val.mode;
235 if (mode == somSCL)
236 sclAssigned = true;
238 if (mode == somSDA)
239 sdaAssigned = true;
241 #if defined(PLATFORM_ESP32)
242 if (mode == somSerial1RX)
243 serial1rxAssigned = true;
245 if (mode == somSerial1TX)
246 serial1txAssigned = true;
247 #endif
250 setLuaUint8Value(&luaMappingChannelOut, arg);
252 // When the selected output channel changes, update the available PWM modes for that pin
253 // Truncate the select options before the ; following On/Off
254 pwmModes[50] = '\0';
256 #if defined(PLATFORM_ESP32)
257 // DShot output (1 option)
258 // ;DShot
259 // ESP8266 enum skips this, so it is never present
260 if (GPIO_PIN_PWM_OUTPUTS[arg-1] != 0) // DShot doesn't work with GPIO0, exclude it
262 pModeString = dshot;
264 else
265 #endif
267 pModeString = no1Option;
269 strcat(pwmModes, pModeString);
271 // SerialIO outputs (1 option)
272 // ;[Serial RX] | [Serial TX]
273 if (GPIO_PIN_PWM_OUTPUTS[arg-1] == U0RXD_GPIO_NUM)
275 pModeString = serial_RX;
277 else if (GPIO_PIN_PWM_OUTPUTS[arg-1] == U0TXD_GPIO_NUM)
279 pModeString = serial_TX;
281 else
283 pModeString = no1Option;
285 strcat(pwmModes, pModeString);
287 // I2C pins (2 options)
288 // ;[I2C SCL] ;[I2C SDA]
289 if (GPIO_PIN_SCL != UNDEF_PIN || GPIO_PIN_SDA != UNDEF_PIN)
291 // If the target defines SCL/SDA then those pins MUST be used
292 if (GPIO_PIN_PWM_OUTPUTS[arg-1] == GPIO_PIN_SCL)
294 pModeString = i2c_SCL;
296 else if (GPIO_PIN_PWM_OUTPUTS[arg-1] == GPIO_PIN_SDA)
298 pModeString = i2c_SDA;
300 else
302 pModeString = no2Options;
305 else
307 // otherwise allow any pin to be either SCL or SDA but only once
308 if (sclAssigned && !sdaAssigned)
310 pModeString = i2c_SDA;
312 else if (sdaAssigned && !sclAssigned)
314 pModeString = i2c_SCL;
316 else if (!sclAssigned && !sdaAssigned)
318 pModeString = i2c_BOTH;
320 else
322 pModeString = no2Options;
325 strcat(pwmModes, pModeString);
327 // nothing to do for unsupported somPwm mode
328 strcat(pwmModes, no1Option);
330 #if defined(PLATFORM_ESP32)
331 // secondary Serial pins (2 options)
332 // ;[SERIAL2 RX] ;[SERIAL2_TX]
333 if (GPIO_PIN_SERIAL1_RX != UNDEF_PIN || GPIO_PIN_SERIAL1_TX != UNDEF_PIN)
335 // If the target defines Serial2 RX/TX then those pins MUST be used
336 if (GPIO_PIN_PWM_OUTPUTS[arg-1] == GPIO_PIN_SERIAL1_RX)
338 pModeString = serial1_RX;
340 else if (GPIO_PIN_PWM_OUTPUTS[arg-1] == GPIO_PIN_SERIAL1_TX)
342 pModeString = serial1_TX;
344 else
346 pModeString = no2Options;
349 else
350 { // otherwise allow any pin to be either RX or TX but only once
351 if (serial1txAssigned && !serial1rxAssigned)
353 pModeString = serial1_RX;
355 else if (serial1rxAssigned && !serial1txAssigned)
357 pModeString = serial1_TX;
360 else if (!serial1rxAssigned && !serial1txAssigned)
362 pModeString = serial1_BOTH;
364 else
366 pModeString = no2Options;
369 strcat(pwmModes, pModeString);
370 #endif
372 // trim off trailing semicolons (assumes pwmModes has at least 1 non-semicolon)
373 for (auto lastPos = strlen(pwmModes)-1; pwmModes[lastPos] == ';'; lastPos--)
375 pwmModes[lastPos] = '\0';
378 // Trigger an event to update the related fields to represent the selected channel
379 devicesTriggerEvent();
382 static void luaparamMappingChannelIn(struct luaPropertiesCommon *item, uint8_t arg)
384 const uint8_t ch = luaMappingChannelOut.properties.u.value - 1;
385 rx_config_pwm_t newPwmCh;
386 newPwmCh.raw = config.GetPwmChannel(ch)->raw;
387 newPwmCh.val.inputChannel = arg - 1; // convert 1-16 -> 0-15
389 config.SetPwmChannelRaw(ch, newPwmCh.raw);
392 static void configureSerialPin(uint8_t sibling, uint8_t oldMode, uint8_t newMode)
394 for (int ch=0 ; ch<GPIO_PIN_PWM_OUTPUTS_COUNT ; ch++)
396 if (GPIO_PIN_PWM_OUTPUTS[ch] == sibling)
398 // Retain as much of the sibling's current config as possible
399 rx_config_pwm_t siblingPinConfig;
400 siblingPinConfig.raw = config.GetPwmChannel(ch)->raw;
402 // If the new mode is serial, the sibling is also forced to serial
403 if (newMode == somSerial)
405 siblingPinConfig.val.mode = somSerial;
407 // If the new mode is not serial, and the sibling is serial, set the sibling to PWM (50Hz)
408 else if (siblingPinConfig.val.mode == somSerial)
410 siblingPinConfig.val.mode = som50Hz;
413 config.SetPwmChannelRaw(ch, siblingPinConfig.raw);
414 break;
418 if (oldMode != newMode)
420 deferExecutionMillis(100, [](){
421 reconfigureSerial();
426 static void luaparamMappingOutputMode(struct luaPropertiesCommon *item, uint8_t arg)
428 UNUSED(item);
429 const uint8_t ch = luaMappingChannelOut.properties.u.value - 1;
430 rx_config_pwm_t newPwmCh;
431 newPwmCh.raw = config.GetPwmChannel(ch)->raw;
432 uint8_t oldMode = newPwmCh.val.mode;
433 newPwmCh.val.mode = arg;
435 // Check if pin == 1/3 and do other pin adjustment accordingly
436 if (GPIO_PIN_PWM_OUTPUTS[ch] == 1)
438 configureSerialPin(3, oldMode, newPwmCh.val.mode);
440 else if (GPIO_PIN_PWM_OUTPUTS[ch] == 3)
442 configureSerialPin(1, oldMode, newPwmCh.val.mode);
444 config.SetPwmChannelRaw(ch, newPwmCh.raw);
447 static void luaparamMappingInverted(struct luaPropertiesCommon *item, uint8_t arg)
449 UNUSED(item);
450 const uint8_t ch = luaMappingChannelOut.properties.u.value - 1;
451 rx_config_pwm_t newPwmCh;
452 newPwmCh.raw = config.GetPwmChannel(ch)->raw;
453 newPwmCh.val.inverted = arg;
455 config.SetPwmChannelRaw(ch, newPwmCh.raw);
458 static void luaparamSetFailsafe(struct luaPropertiesCommon *item, uint8_t arg)
460 luaCmdStep_e newStep;
461 const char *msg;
462 if (arg == lcsClick)
464 newStep = lcsAskConfirm;
465 msg = "Set failsafe to curr?";
467 else if (arg == lcsConfirmed)
469 // This is generally not seen by the user, since we'll disconnect to commit config
470 // and the handset will send another lcdQuery that will overwrite it with idle
471 newStep = lcsExecuting;
472 msg = "Setting failsafe";
474 for (int ch=0; ch<GPIO_PIN_PWM_OUTPUTS_COUNT; ++ch)
476 rx_config_pwm_t newPwmCh;
477 // The value must fit into the 10 bit range of the failsafe
478 newPwmCh.raw = config.GetPwmChannel(ch)->raw;
479 newPwmCh.val.failsafe = CRSF_to_UINT10(constrain(ChannelData[config.GetPwmChannel(ch)->val.inputChannel], CRSF_CHANNEL_VALUE_MIN, CRSF_CHANNEL_VALUE_MAX));
480 //DBGLN("FSCH(%u) crsf=%u us=%u", ch, ChannelData[ch], newPwmCh.val.failsafe+988U);
481 config.SetPwmChannelRaw(ch, newPwmCh.raw);
484 else
486 newStep = lcsIdle;
487 msg = STR_EMPTYSPACE;
490 sendLuaCommandResponse((struct luaItem_command *)item, newStep, msg);
493 #endif // GPIO_PIN_PWM_OUTPUTS
495 #if defined(POWER_OUTPUT_VALUES)
497 static void luaparamSetPower(struct luaPropertiesCommon* item, uint8_t arg)
499 UNUSED(item);
500 uint8_t newPower = arg + POWERMGNT::getMinPower();
501 if (newPower > POWERMGNT::getMaxPower())
503 newPower = PWR_MATCH_TX;
506 config.SetPower(newPower);
507 // POWERMGNT::setPower() will be called in updatePower() in the main loop
510 #endif // POWER_OUTPUT_VALUES
512 static void registerLuaParameters()
514 registerLUAParameter(&luaSerialProtocol, [](struct luaPropertiesCommon* item, uint8_t arg){
515 config.SetSerialProtocol((eSerialProtocol)arg);
516 if (config.IsModified()) {
517 deferExecutionMillis(100, [](){
518 reconfigureSerial();
523 #if defined(PLATFORM_ESP32)
524 if (RX_HAS_SERIAL1)
526 registerLUAParameter(&luaSerial1Protocol, [](struct luaPropertiesCommon* item, uint8_t arg){
527 config.SetSerial1Protocol((eSerial1Protocol)arg);
528 if (config.IsModified()) {
529 deferExecutionMillis(100, [](){
530 reconfigureSerial1();
535 #endif
537 registerLUAParameter(&luaSBUSFailsafeMode, [](struct luaPropertiesCommon* item, uint8_t arg){
538 config.SetFailsafeMode((eFailsafeMode)arg);
541 registerLUAParameter(&luaTargetSysId, [](struct luaPropertiesCommon* item, uint8_t arg){
542 config.SetTargetSysId((uint8_t)arg);
544 registerLUAParameter(&luaSourceSysId, [](struct luaPropertiesCommon* item, uint8_t arg){
545 config.SetSourceSysId((uint8_t)arg);
548 if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)
550 registerLUAParameter(&luaAntennaMode, [](struct luaPropertiesCommon* item, uint8_t arg){
551 config.SetAntennaMode(arg);
555 // Gemini Mode
556 if (isDualRadio())
558 registerLUAParameter(&luaDiversityMode, [](struct luaPropertiesCommon* item, uint8_t arg){
559 config.SetAntennaMode(arg); // Reusing SetAntennaMode since both GPIO_PIN_ANTENNA_SELECT and GPIO_PIN_NSS_2 will not be defined together.
563 #if defined(POWER_OUTPUT_VALUES)
564 luadevGeneratePowerOpts(&luaTlmPower);
565 registerLUAParameter(&luaTlmPower, &luaparamSetPower);
566 #endif
568 // Teamrace
569 registerLUAParameter(&luaTeamraceFolder);
570 registerLUAParameter(&luaTeamraceChannel, [](struct luaPropertiesCommon* item, uint8_t arg) {
571 config.SetTeamraceChannel(arg + AUX2);
572 }, luaTeamraceFolder.common.id);
573 registerLUAParameter(&luaTeamracePosition, [](struct luaPropertiesCommon* item, uint8_t arg) {
574 config.SetTeamracePosition(arg);
575 }, luaTeamraceFolder.common.id);
577 #if defined(GPIO_PIN_PWM_OUTPUTS)
578 if (OPT_HAS_SERVO_OUTPUT)
580 luaparamMappingChannelOut(&luaMappingOutputMode.common, luaMappingChannelOut.properties.u.value);
581 registerLUAParameter(&luaMappingFolder);
582 registerLUAParameter(&luaMappingChannelOut, &luaparamMappingChannelOut, luaMappingFolder.common.id);
583 registerLUAParameter(&luaMappingChannelIn, &luaparamMappingChannelIn, luaMappingFolder.common.id);
584 registerLUAParameter(&luaMappingOutputMode, &luaparamMappingOutputMode, luaMappingFolder.common.id);
585 registerLUAParameter(&luaMappingInverted, &luaparamMappingInverted, luaMappingFolder.common.id);
586 registerLUAParameter(&luaSetFailsafe, &luaparamSetFailsafe);
588 #endif
590 registerLUAParameter(&luaBindStorage, [](struct luaPropertiesCommon* item, uint8_t arg) {
591 config.SetBindStorage((rx_config_bindstorage_t)arg);
593 registerLUAParameter(&luaBindMode, [](struct luaPropertiesCommon* item, uint8_t arg){
594 // Complete when TX polls for status i.e. going back to idle, because we're going to lose connection
595 if (arg == lcsQuery) {
596 deferExecutionMillis(200, EnterBindingModeSafely);
598 sendLuaCommandResponse(&luaBindMode, arg < 5 ? lcsExecuting : lcsIdle, arg < 5 ? "Entering..." : "");
601 registerLUAParameter(&luaModelNumber);
602 registerLUAParameter(&luaELRSversion);
603 registerLUAParameter(nullptr);
606 static void updateBindModeLabel()
608 if (config.IsOnLoan())
609 luaBindMode.common.name = "Return Model";
610 else
611 luaBindMode.common.name = "Enter Bind Mode";
614 static int event()
616 setLuaTextSelectionValue(&luaSerialProtocol, config.GetSerialProtocol());
617 #if defined(PLATFORM_ESP32)
618 if (RX_HAS_SERIAL1)
620 setLuaTextSelectionValue(&luaSerial1Protocol, config.GetSerial1Protocol());
622 #endif
624 setLuaTextSelectionValue(&luaSBUSFailsafeMode, config.GetFailsafeMode());
626 if (GPIO_PIN_ANT_CTRL != UNDEF_PIN)
628 setLuaTextSelectionValue(&luaAntennaMode, config.GetAntennaMode());
631 // Gemini Mode
632 if (isDualRadio())
634 setLuaTextSelectionValue(&luaDiversityMode, config.GetAntennaMode()); // Reusing SetAntennaMode since both GPIO_PIN_ANTENNA_SELECT and GPIO_PIN_NSS_2 will not be defined together.
637 #if defined(POWER_OUTPUT_VALUES)
638 // The last item (for MatchTX) will be MaxPower - MinPower + 1
639 uint8_t luaPwrVal = (config.GetPower() == PWR_MATCH_TX) ? POWERMGNT::getMaxPower() + 1 : config.GetPower();
640 setLuaTextSelectionValue(&luaTlmPower, luaPwrVal - POWERMGNT::getMinPower());
641 #endif
643 // Teamrace
644 setLuaTextSelectionValue(&luaTeamraceChannel, config.GetTeamraceChannel() - AUX2);
645 setLuaTextSelectionValue(&luaTeamracePosition, config.GetTeamracePosition());
647 #if defined(GPIO_PIN_PWM_OUTPUTS)
648 if (OPT_HAS_SERVO_OUTPUT)
650 const rx_config_pwm_t *pwmCh = config.GetPwmChannel(luaMappingChannelOut.properties.u.value - 1);
651 setLuaUint8Value(&luaMappingChannelIn, pwmCh->val.inputChannel + 1);
652 setLuaTextSelectionValue(&luaMappingOutputMode, pwmCh->val.mode);
653 setLuaTextSelectionValue(&luaMappingInverted, pwmCh->val.inverted);
655 #endif
657 if (config.GetModelId() == 255)
659 setLuaStringValue(&luaModelNumber, "Off");
661 else
663 itoa(config.GetModelId(), modelString, 10);
664 setLuaStringValue(&luaModelNumber, modelString);
666 setLuaTextSelectionValue(&luaBindStorage, config.GetBindStorage());
667 updateBindModeLabel();
669 if (config.GetSerialProtocol() == PROTOCOL_MAVLINK)
671 setLuaUint8Value(&luaSourceSysId, config.GetSourceSysId() == 0 ? 255 : config.GetSourceSysId()); //display Source sysID if 0 display 255 to mimic logic in SerialMavlink.cpp
672 setLuaUint8Value(&luaTargetSysId, config.GetTargetSysId() == 0 ? 1 : config.GetTargetSysId()); //display Target sysID if 0 display 1 to mimic logic in SerialMavlink.cpp
673 LUA_FIELD_SHOW(luaSourceSysId)
674 LUA_FIELD_SHOW(luaTargetSysId)
676 else
678 LUA_FIELD_HIDE(luaSourceSysId)
679 LUA_FIELD_HIDE(luaTargetSysId)
682 return DURATION_IMMEDIATELY;
685 static int timeout()
687 luaHandleUpdateParameter();
688 // Receivers can only `UpdateParamReq == true` every 4th packet due to the transmitter cadence in 1:2
689 // Channels, Downlink Telemetry Slot, Uplink Telemetry (the write command), Downlink Telemetry Slot...
690 // (interval * 4 / 1000) or 1 second if not connected
691 return (connectionState == connected) ? ExpressLRS_currAirRate_Modparams->interval / 250 : 1000;
694 static int start()
696 registerLuaParameters();
697 event();
698 return DURATION_IMMEDIATELY;
701 device_t LUA_device = {
702 .initialize = nullptr,
703 .start = start,
704 .event = event,
705 .timeout = timeout
708 #endif