Skip to content

Commit 990a6d5

Browse files
authored
Crossfire LUA Compatibility (ExpressLRS#895)
* Crossfire LUA Compatibility LUA Handling on TX - Move LUA specific functions to LUA library - Simplification of the LUA library - Cleanup and clarify the LUA code handling - Adjust status code and info in polling callback based on actual state - Fix-up some debugging - Updates to LUA handling based on research - Rework the webserver to use AsyncWebServer, so we can exit wifi update & joystick from LUA - Reduce the SPIFFS partition for more app flash LUA Changes - Add validation of packet Once we've already seen a packet and we have the expected parent and type we can validate them on subsequent messages. This fixes a problem where we get missed chunks and if we miss chunk zero then the rest of the chunks are shifted down and causes an error in the script. - INFO type is not to be changes - Add code to detect missing chunks and ignore the update if there are any - Add command running indicator - Changes to support current CRSF protocol implementation MIscellaneous - Reduce leeway for 115k baud @ 250Hz - Update timer for reboot * No reload on "Back", and fast load on save * Revert timer disable check in BLE start code * Fix typo * Fix for old crossfire LUA commands * Fix corruption of valid packet rates string due to changing rate causing problems on the serial line * Don't respond to LUA till after we've effectively changed the serial packet rate * Exit a field that is being edited only reloads itself Cleanup statusComplete
1 parent 7215332 commit 990a6d5

11 files changed

Lines changed: 602 additions & 615 deletions

File tree

src/lib/CRSF/CRSF.cpp

Lines changed: 4 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ bool CRSF::CRSFstate = false;
9696

9797
uint8_t CRSF::MspData[ELRS_MSP_BUFFER] = {0};
9898
uint8_t CRSF::MspDataLength = 0;
99-
100-
uint32_t CRSF::luaHiddenFlags = 0;
10199
#endif // CRSF_TX_MODULE
102100

103101

@@ -244,191 +242,6 @@ void CRSF::packetQueueExtended(uint8_t type, void *data, uint8_t len)
244242
#endif
245243
}
246244

247-
uint8_t CRSF::setLuaHiddenFlag(uint8_t id, bool value){
248-
luaHiddenFlags ^= (-value ^ luaHiddenFlags) & (1 << ((id-1)));
249-
return value;
250-
}
251-
252-
void CRSF::getLuaTextSelectionStructToArray(const void * luaStruct, uint8_t *outarray){
253-
struct tagLuaItem_textSelection *p1 = (struct tagLuaItem_textSelection*)luaStruct;
254-
char *next = stpcpy((char *)outarray,p1->label1) + 1;
255-
next = stpcpy(next,p1->textOption) + 1;
256-
memcpy(next,&p1->luaProperties2,sizeof(p1->luaProperties2));
257-
next+=sizeof(p1->luaProperties2);
258-
*next++=0; // default value
259-
stpcpy(next,p1->label2);
260-
261-
//outarray[4+(strlen(p1->label1)+1)+(strlen(p1->textOption)+1)] = (uint8_t)luaValues[p1->luaProperties1.id];
262-
}
263-
264-
void CRSF::getLuaCommandStructToArray(const void * luaStruct, uint8_t *outarray){
265-
struct tagLuaItem_command *p1 = (struct tagLuaItem_command*)luaStruct;
266-
char *next = stpcpy((char *)outarray,p1->label1) + 1;
267-
memcpy(next,&p1->luaProperties2,sizeof(p1->luaProperties2));
268-
next+=sizeof(p1->luaProperties2);
269-
stpcpy(next,p1->label2);
270-
271-
//outarray[4+(strlen(p1->label1)+1)] = (uint8_t)luaValues[p1->luaProperties1.id];
272-
}
273-
274-
void CRSF::getLuaUint8StructToArray(const void * luaStruct, uint8_t *outarray){
275-
struct tagLuaItem_uint8 *p1 = (struct tagLuaItem_uint8*)luaStruct;
276-
char *next = stpcpy((char *)outarray,p1->label1) + 1;
277-
memcpy(next,&p1->luaProperties2,sizeof(p1->luaProperties2));
278-
next+=sizeof(p1->luaProperties2);
279-
*next++=0; // default value
280-
stpcpy(next,p1->label2);
281-
282-
//outarray[4+(strlen(p1->label1)+1)] = (uint8_t)luaValues[p1->luaProperties1.id];
283-
}
284-
285-
void CRSF::getLuaUint16StructToArray(const void * luaStruct, uint8_t *outarray){
286-
struct tagLuaItem_uint16 *p1 = (struct tagLuaItem_uint16*)luaStruct;
287-
char *next = stpcpy((char *)outarray,p1->label1) + 1;
288-
memcpy(next,&p1->luaProperties2,sizeof(p1->luaProperties2));
289-
next+=sizeof(p1->luaProperties2);
290-
*next++=0; // default value
291-
stpcpy(next,p1->label2);
292-
293-
//[4+(strlen(p1->label1)+1)] = (uint8_t)(luaValues[p1->luaProperties1.id] >> 8);
294-
//outarray[4+(strlen(p1->label1)+2)] = (uint8_t)luaValues[p1->luaProperties1.id];
295-
}
296-
297-
void CRSF::getLuaStringStructToArray(const void * luaStruct, uint8_t *outarray){
298-
struct tagLuaItem_string *p1 = (struct tagLuaItem_string*)luaStruct;
299-
char *next = stpcpy((char *)outarray,p1->label1) + 1;
300-
stpcpy(next,p1->label2);
301-
}
302-
void CRSF::getLuaFolderStructToArray(const void * luaStruct, uint8_t *outarray){
303-
struct tagLuaItem_string *p1 = (struct tagLuaItem_string*)luaStruct;
304-
stpcpy((char *)outarray,p1->label1);
305-
}
306-
307-
//sendCRSF param can take anytype of lua field settings
308-
uint8_t CRSF::sendCRSFparam(crsf_frame_type_e frame,uint8_t fieldchunk, crsf_value_type_e dataType, const void * luaData, uint8_t wholePacketSize)
309-
{
310-
if (!CRSF::CRSFstate)
311-
{
312-
return 0;
313-
}
314-
uint8_t LUArespLength;
315-
uint8_t chunks = 0;
316-
uint8_t currentPacketSize;
317-
318-
uint16_t chunkMax = maxPacketBytes-8;
319-
320-
/**
321-
*calculate how many chunks needed for this field
322-
*/
323-
chunks = ((wholePacketSize-2)/(chunkMax));
324-
if((wholePacketSize-2) % (chunkMax)){
325-
chunks = chunks + 1;
326-
}
327-
328-
//calculate how much byte this packet contains
329-
if((chunks - (fieldchunk+1)) > 0){
330-
currentPacketSize = chunkMax;
331-
} else {
332-
if((wholePacketSize-2) % (chunkMax)){
333-
currentPacketSize = (wholePacketSize-2) % (chunkMax);
334-
} else {
335-
currentPacketSize = chunkMax;
336-
}
337-
}
338-
LUArespLength = 2+2+ currentPacketSize; //2 bytes of header, fieldsetup1(fieldid, fieldchunk),
339-
// chunk-ed packets below
340-
//fieldsetup1(fieldparent,fieldtype),field name,
341-
//fieldsetup2(value,min,max,default),field unit
342-
//create outbuffer size
343-
uint8_t chunkBuffer[wholePacketSize];
344-
uint8_t outBuffer[currentPacketSize + 5 + 2 + 2];
345-
//it is byte op, we can use memcpy with index to
346-
// destination memory.
347-
switch(dataType){
348-
case CRSF_TEXT_SELECTION:
349-
{
350-
getLuaTextSelectionStructToArray(luaData, chunkBuffer);
351-
break;
352-
}
353-
case CRSF_COMMAND:
354-
{
355-
getLuaCommandStructToArray(luaData, chunkBuffer);
356-
break;
357-
}
358-
case CRSF_UINT8:
359-
{
360-
getLuaUint8StructToArray(luaData,chunkBuffer);
361-
break;
362-
}
363-
case CRSF_UINT16:
364-
{
365-
getLuaUint16StructToArray(luaData,chunkBuffer);
366-
break;
367-
}
368-
// we dont have to include this for now. since we dont need it yet?
369-
case CRSF_INT8:
370-
{
371-
//getLuaint8StructToArray(luaData,chunkBuffer);
372-
break;
373-
}
374-
case CRSF_INT16:
375-
{
376-
//getLuaint16StructToArray(luaData,chunkBuffer);
377-
break;
378-
}
379-
case CRSF_FLOAT:
380-
{
381-
//getLuaFloatStructToArray(luaData,chunkBuffer);
382-
break;
383-
}
384-
//
385-
case CRSF_STRING:
386-
case CRSF_INFO:
387-
{
388-
getLuaStringStructToArray(luaData,chunkBuffer);
389-
break;
390-
}
391-
case CRSF_FOLDER:
392-
{
393-
getLuaFolderStructToArray(luaData,chunkBuffer);
394-
break;
395-
}
396-
case CRSF_OUT_OF_RANGE:
397-
default:
398-
break;
399-
400-
}
401-
outBuffer[0] = CRSF_ADDRESS_RADIO_TRANSMITTER;
402-
outBuffer[1] = LUArespLength + 2; //received as #data in lua
403-
outBuffer[2] = frame; //received as command in lua
404-
// all below received as data in lua
405-
outBuffer[3] = CRSF_ADDRESS_RADIO_TRANSMITTER;
406-
outBuffer[4] = CRSF_ADDRESS_CRSF_TRANSMITTER;
407-
408-
outBuffer[5] = ((struct tagLuaProperties1 *)luaData)->id;
409-
outBuffer[6] = ((chunks - (fieldchunk+1))); //remaining chunk to send;
410-
if (fieldchunk == 0) {
411-
outBuffer[7] = ((struct tagLuaProperties1 *)luaData)->parent;
412-
outBuffer[8] = ((struct tagLuaProperties1 *)luaData)->type;
413-
outBuffer[8] += ((luaHiddenFlags >>((((struct tagLuaProperties1 *)luaData)->id)-1)) & 1)*128;
414-
memcpy(outBuffer+9,chunkBuffer,currentPacketSize-2);
415-
} else {
416-
memcpy(outBuffer+7,chunkBuffer+((fieldchunk*chunkMax))-2,currentPacketSize);
417-
}
418-
uint8_t crc = crsf_crc.calc(&outBuffer[2], LUArespLength + 1);
419-
outBuffer[LUArespLength + 3] = crc;
420-
421-
#ifdef PLATFORM_ESP32
422-
portENTER_CRITICAL(&FIFOmux);
423-
#endif
424-
SerialOutFIFO.push(LUArespLength + 4);
425-
SerialOutFIFO.pushBytes(outBuffer, LUArespLength + 4);
426-
#ifdef PLATFORM_ESP32
427-
portEXIT_CRITICAL(&FIFOmux);
428-
#endif
429-
return ((chunks - (fieldchunk+1)));
430-
}
431-
432245
void ICACHE_RAM_ATTR CRSF::sendTelemetryToTX(uint8_t *data)
433246
{
434247
if (data[CRSF_TELEMETRY_LENGTH_INDEX] > CRSF_PAYLOAD_SIZE_MAX)
@@ -882,9 +695,11 @@ void ICACHE_RAM_ATTR CRSF::duplex_set_TX()
882695
void ICACHE_RAM_ATTR CRSF::adjustMaxPacketSize()
883696
{
884697
uint32_t UARTrequestedBaud = TxToHandsetBauds[UARTcurrentBaudIdx];
885-
// baud / 10bits-per-byte / 2 windows (1RX, 1TX) / rate * 0.85 (leeway)
886-
int maxSize = UARTrequestedBaud / 10 / 2 / (1000000/RequestedRCpacketInterval) * 85 / 100;
698+
// baud / 10bits-per-byte / 2 windows (1RX, 1TX) / rate * 0.80 (leeway)
699+
int maxSize = UARTrequestedBaud / 10 / 2 / (1000000/RequestedRCpacketInterval) * 80 / 100;
887700
maxPacketBytes = maxSize > CRSF_MAX_PACKET_LEN ? CRSF_MAX_PACKET_LEN : maxSize;
701+
// we need a minimum of 10 bytes otherwise our LUA will not make progress and at 8 we'd get a divide by 0!
702+
maxPacketBytes = maxPacketBytes < 10 ? 10 : maxPacketBytes;
888703
DBGLN("Adjusted max packet size %u", maxPacketBytes);
889704
}
890705

src/lib/CRSF/CRSF.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ class CRSF
7474
void ICACHE_RAM_ATTR sendLinkStatisticsToTX();
7575
void ICACHE_RAM_ATTR sendTelemetryToTX(uint8_t *data);
7676

77-
uint8_t sendCRSFparam(crsf_frame_type_e frame,uint8_t fieldchunk, crsf_value_type_e dataType, const void * luaData, uint8_t wholePacketSize);
7877
static void packetQueueExtended(uint8_t type, void *data, uint8_t len);
7978

8079
static void ICACHE_RAM_ATTR sendSetVTXchannel(uint8_t band, uint8_t channel);
@@ -106,9 +105,7 @@ class CRSF
106105
static void AddMspMessage(mspPacket_t* packet);
107106
static void ResetMspQueue();
108107
static volatile uint32_t OpenTXsyncLastSent;
109-
110-
uint8_t setLuaHiddenFlag(uint8_t id, bool value);
111-
108+
static uint8_t GetMaxPacketBytes() { return maxPacketBytes; }
112109
#endif
113110
private:
114111
Stream *_dev;
@@ -154,22 +151,6 @@ class CRSF
154151
static bool UARTwdt();
155152
static void ICACHE_RAM_ATTR adjustMaxPacketSize();
156153

157-
static uint32_t luaHiddenFlags;
158-
159-
void getLuaTextSelectionStructToArray(const void * luaStruct, uint8_t *outarray);
160-
void getLuaCommandStructToArray(const void * luaStruct, uint8_t *outarray);
161-
void getLuaUint8StructToArray(const void * luaStruct, uint8_t *outarray);
162-
void getLuaUint16StructToArray(const void * luaStruct, uint8_t *outarray);
163-
void getLuaStringStructToArray(const void * luaStruct, uint8_t *outarray);
164-
void getLuaFolderStructToArray(const void * luaStruct, uint8_t *outarray);
165-
/** we dont need these yet for OUR LUA, and it is not defined yet
166-
void getLuaUint8StructToArray(const void * luaStruct, uint8_t *outarray);
167-
void getLuaint8StructToArray(const void * luaStruct, uint8_t *outarray);
168-
void getLuaUint16StructToArray(const void * luaStruct, uint8_t *outarray);
169-
void getLuaint16StructToArray(const void * luaStruct, uint8_t *outarray);
170-
void getLuaFloatStructToArray(const void * luaStruct, uint8_t *outarray);
171-
*/
172-
173154
#endif
174155

175156
static void flush_port_input(void);

src/lib/CrsfProtocol/crsf_protocol.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ typedef enum
180180
CRSF_OUT_OF_RANGE = 127,
181181
} crsf_value_type_e;
182182

183+
// These flags are or'ed with the field type above to hide the field from the normal LUA view
184+
#define CRSF_FIELD_HIDDEN 0x80 // marked as hidden in all LUA responses
185+
#define CRSF_FIELD_ELRS_HIDDEN 0x40 // marked as hidden when talking to ELRS specific LUA
186+
183187
/**
184188
* Define the shape of a standard header
185189
*/
@@ -364,6 +368,7 @@ struct tagLuaItem_command {
364368
struct tagLuaProperties1 luaProperties1;
365369
const char* const label1; //command name
366370
struct tagLuaCommandProperties luaProperties2;
371+
const char *defaultInfo; //default command info message
367372
const char *label2; //command info
368373
uint8_t size;
369374
} PACKED;

src/lib/LED/LED.h

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,38 @@ void updateLEDs(uint32_t now, connectionState_e connectionState, uint8_t rate, u
8989
void startupLEDs()
9090
{
9191
#if WS2812_LED_IS_USED || (defined(PLATFORM_ESP32) && defined(GPIO_PIN_LED))
92-
// do startup blinkies for fun
93-
constexpr uint32_t colors[8] =
94-
{
95-
0xFFFFFF, // white
96-
0xFF00FF, // magenta
97-
0x8000FF, // violet
98-
0x0000FF, // blue
99-
0x00FF00, // green
100-
0xFFFF00, // yellow
101-
0xFF8000, // orange
102-
0xFF0000 // red
103-
};
104-
constexpr uint8_t N_COLORS = sizeof(colors)/sizeof(colors[0]);
105-
10692
WS281Binit();
107-
for (uint8_t i = 0; i < N_COLORS; i++)
108-
{
109-
WS281BsetLED(colors[i]);
110-
delay(1000/N_COLORS);
111-
}
112-
for (uint8_t i = 0; i < N_COLORS; i++)
93+
94+
#ifdef PLATFORM_ESP32
95+
// Only do the blinkies if it was NOT a software reboot
96+
if (esp_reset_reason() != ESP_RST_SW)
97+
#endif
11398
{
114-
WS281BsetLED(colors[N_COLORS-i-1]);
115-
delay(1000/N_COLORS);
99+
// do startup blinkies for fun
100+
constexpr uint32_t colors[8] =
101+
{
102+
0xFFFFFF, // white
103+
0xFF00FF, // magenta
104+
0x8000FF, // violet
105+
0x0000FF, // blue
106+
0x00FF00, // green
107+
0xFFFF00, // yellow
108+
0xFF8000, // orange
109+
0xFF0000 // red
110+
};
111+
constexpr uint8_t N_COLORS = sizeof(colors)/sizeof(colors[0]);
112+
113+
for (uint8_t i = 0; i < N_COLORS; i++)
114+
{
115+
WS281BsetLED(colors[i]);
116+
delay(1000/N_COLORS);
117+
}
118+
for (uint8_t i = 0; i < N_COLORS; i++)
119+
{
120+
WS281BsetLED(colors[N_COLORS-i-1]);
121+
delay(1000/N_COLORS);
122+
}
123+
WS281BsetLED((uint32_t)0);
116124
}
117-
WS281BsetLED((uint32_t)0);
118125
#endif
119126
}

0 commit comments

Comments
 (0)