Skip to content

Commit 8852dda

Browse files
authored
Reduce memory use of the Lua script slightly (ExpressLRS#1019)
* Reduce memory use of string concats * Remove duplicate populateHandler() * Only call populateHandler where needed * Really only needed one populateHandler * Allow reusing of previous strings and select opts * Remove getLastPos(), not available on COLORLCD
1 parent e9ddd15 commit 8852dda

2 files changed

Lines changed: 73 additions & 74 deletions

File tree

src/lib/LUA/lua.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static uint8_t *luaStringStructToArray(const void *luaStruct, uint8_t *next)
8383
static uint8_t sendCRSFparam(crsf_frame_type_e frameType, uint8_t fieldChunk, struct luaPropertiesCommon *luaData)
8484
{
8585
uint8_t dataType = luaData->type & ~(CRSF_FIELD_HIDDEN|CRSF_FIELD_ELRS_HIDDEN);
86-
86+
8787
// 256 max payload + (FieldID + ChunksRemain + Parent + Type)
8888
// Chunk 1: (FieldID + ChunksRemain + Parent + Type) + fieldChunk0 data
8989
// Chunk 2-N: (FieldID + ChunksRemain) + fieldChunk1 data
@@ -240,10 +240,8 @@ bool luaHandleUpdateParameter()
240240
{
241241
return false;
242242
}
243-
244-
populateHandler();
245-
246-
switch(crsf.ParameterUpdateData[0])
243+
244+
switch(crsf.ParameterUpdateData[0])
247245
{
248246
case CRSF_FRAMETYPE_PARAMETER_WRITE:
249247
if (crsf.ParameterUpdateData[1] == 0)

src/lua/elrsV2.lua

Lines changed: 70 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ local fieldId = 1
2828
local fieldChunk = 0
2929
local fieldData = {}
3030
local fields = {}
31-
local badPkt = 0
32-
local goodPkt = 0
31+
local devices = {}
32+
local goodBadPkt = "?/???"
3333
local elrsFlags = 0
34-
local elrsFlagsInfo = "no"
34+
local elrsFlagsInfo
3535
local fields_count = 0
3636
local backButtonId = 2
3737
local devicesRefreshTimeout = 50
@@ -50,9 +50,8 @@ local textYoffset = 1
5050
local textSize = 8
5151
local lcdIsColor
5252

53-
local devices = { }
54-
55-
local function clearAllField()
53+
local function allocateFields()
54+
fields = {}
5655
for i=1, fields_count + 2 + #devices do
5756
fields[i] = { }
5857
end
@@ -135,31 +134,56 @@ local function selectField(step)
135134
field = getField(newLineIndex)
136135
until newLineIndex == lineIndex or (field and field.name)
137136
lineIndex = newLineIndex
138-
if lineIndex > maxLineIndex + pageOffset then -- NOTE: increased from 7 to 11 to allow 11 lines in Horus display
139-
pageOffset = lineIndex - maxLineIndex -- NOTE: increased from 7 to 11 to allow 11 lines in Horus display
137+
if lineIndex > maxLineIndex + pageOffset then
138+
pageOffset = lineIndex - maxLineIndex
140139
elseif lineIndex <= pageOffset then
141140
pageOffset = lineIndex - 1
142141
end
143142
end
144143

145-
local function split(str)
146-
local t = {}
147-
local i = 1
148-
for s in string.gmatch(str, "([^;]+)") do
149-
t[i] = s
150-
i = i + 1
144+
local function fieldStrFF(data, offset, last)
145+
while data[offset] ~= 0 do
146+
offset = offset + 1
151147
end
152-
return t
148+
return last, offset + 1
153149
end
154150

155-
local function fieldGetString(data, offset)
151+
local function fieldGetSelectOpts(data, offset, last)
152+
if last then
153+
return fieldStrFF(data, offset, last)
154+
end
155+
156+
-- Split a table of byte values (string) with ; separator into a table
157+
local r = {}
158+
local opt = ''
159+
local b = data[offset]
160+
while b ~= 0 do
161+
if b == 59 then -- ';'
162+
r[#r+1] = opt
163+
opt = ''
164+
else
165+
opt = opt .. string.char(b)
166+
end
167+
offset = offset + 1
168+
b = data[offset]
169+
end
170+
171+
r[#r+1] = opt
172+
return r, offset + 1
173+
end
174+
175+
local function fieldGetString(data, offset, last)
176+
if last then
177+
return fieldStrFF(data, offset, last)
178+
end
179+
156180
local result = ""
157181
while data[offset] ~= 0 do
158182
result = result .. string.char(data[offset])
159183
offset = offset + 1
160184
end
161-
offset = offset + 1
162-
return result, offset
185+
186+
return result, offset + 1
163187
end
164188

165189
local function getBitBin(data, bitPosition)
@@ -177,7 +201,7 @@ local function getBitBin(data, bitPosition)
177201
}
178202
return device
179203
end
180-
204+
181205
local function getDevice(name)
182206
for i=1, #devices do
183207
if devices[i].name == name then
@@ -200,7 +224,7 @@ local function fieldUnsignedLoad(field, data, offset, size)
200224
field.min = fieldGetValue(data, offset+size, size)
201225
field.max = fieldGetValue(data, offset+2*size, size)
202226
field.default = fieldGetValue(data, offset+3*size, size)
203-
field.unit, offset = fieldGetString(data, offset+4*size)
227+
field.unit, offset = fieldGetString(data, offset+4*size, field.unit)
204228
field.step = 1
205229
end
206230

@@ -239,9 +263,7 @@ local function fieldSignedSave(field, size)
239263
end
240264

241265
local function fieldIntDisplay(field, y, attr)
242-
-- lcd.drawNumber(COL2, y, field.value, LEFT + attr) -- NOTE: original code getLastPos not available in Horus
243-
-- lcd.drawText(lcd.getLastPos(), y, field.unit, attr) -- NOTE: original code getLastPos not available in Horus
244-
lcd.drawText(COL2, y, field.value .. field.unit, attr) -- NOTE: Concenated fields instead of get lastPos
266+
lcd.drawText(COL2, y, field.value .. field.unit, attr)
245267
end
246268

247269
-- UINT8
@@ -292,7 +314,7 @@ local function fieldFloatLoad(field, data, offset)
292314
field.prec = 3
293315
end
294316
field.step = fieldGetValue(data, offset+17, 4)
295-
field.unit, offset = fieldGetString(data, offset+21)
317+
field.unit, offset = fieldGetString(data, offset+21, field.unit)
296318
end
297319

298320
local function formatFloat(num, decimals)
@@ -311,26 +333,20 @@ end
311333

312334
-- TEXT SELECTION
313335
local function fieldTextSelectionLoad(field, data, offset)
314-
local values
315-
values, offset = fieldGetString(data, offset)
316-
if values ~= "" then
317-
field.values = split(values)
318-
end
336+
field.values, offset = fieldGetSelectOpts(data, offset, field.values)
319337
field.value = data[offset]
320338
field.min = data[offset+1]
321339
field.max = data[offset+2]
322340
field.default = data[offset+3]
323-
field.unit, offset = fieldGetString(data, offset+4)
341+
field.unit, offset = fieldGetString(data, offset+4, field.unit)
324342
end
325343

326344
local function fieldTextSelectionSave(field)
327345
crossfireTelemetryPush(0x2D, { deviceId, handsetId, field.id, field.value })
328346
end
329347

330348
local function fieldTextSelectionDisplay(field, y, attr)
331-
-- lcd.drawText(COL2, y, field.values[field.value+1], attr) -- NOTE: original code getLastPos not available in Horus
332-
-- lcd.drawText(lcd.getLastPos(), y, field.unit, attr) -- NOTE: original code getLastPos not available in Horus
333-
lcd.drawText(COL2, y, field.values[field.value+1] .. field.unit, attr) -- NOTE: Concenated fields instead of get lastPos
349+
lcd.drawText(COL2, y, field.values[field.value+1] .. field.unit, attr)
334350
end
335351

336352
-- STRING
@@ -412,7 +428,6 @@ end
412428

413429
local function changeDeviceId(devId) --change to selected device ID
414430
folderAccess = 0
415-
clearAllField()
416431
deviceIsELRS = false
417432
elrsFlags = 0
418433
--if the selected device ID (target) is a TX Module, we use our Lua ID, so TX Flag that user is using our LUA
@@ -435,7 +450,6 @@ local function parseDeviceInfoMessage(data)
435450
local offset
436451
local id = data[2]
437452
local devicesName = ""
438-
-- deviceId = data[2]
439453
devicesName, offset = fieldGetString(data, 3)
440454
local device = getDevice(devicesName)
441455
if device == nil then
@@ -445,10 +459,13 @@ local function parseDeviceInfoMessage(data)
445459
if deviceId == id then
446460
deviceName = devicesName
447461
deviceIsELRS = fieldGetValue(data,offset,4) == 0x454C5253 -- SerialNumber = 'E L R S'
448-
fields_count = data[offset+12]
462+
local newFieldCount = data[offset+12]
449463
reloadAllField()
450-
clearAllField()
451-
fields[fields_count+1] = {id = fields_count+1, name="Other Devices", parent = 255, type=16} -- add other devices folders
464+
if newFieldCount ~= fields_count then
465+
fields_count = newFieldCount
466+
allocateFields()
467+
fields[fields_count+1] = {id = fields_count+1, name="Other Devices", parent = 255, type=16} -- add other devices folders
468+
end
452469
end
453470
end
454471

@@ -512,27 +529,10 @@ local function parseParameterInfoMessage(data)
512529
return -- no data extraction
513530
end
514531
field.id = fieldId
515-
local parent = fieldData[1]
516-
local type = fieldData[2] % 128
517-
local hidden = (bit32.rshift(fieldData[2], 7) == 1)
518-
if field.name ~= nil then -- already seen this field before, so we can validate this packet is correct
519-
if field.parent ~= parent or field.type ~= type or field.hidden ~= hidden then
520-
fieldData = {}
521-
return -- no data extraction
522-
end
523-
end
524-
field.parent = parent
525-
field.type = type
526-
field.hidden = hidden
527-
local name, i = fieldGetString(fieldData, 3)
528-
if name ~= "" then
529-
local indent = ""
530-
while parent ~= 0 do
531-
indent = indent .. " "
532-
parent = fields[parent].parent
533-
end
534-
field.name = indent .. name
535-
end
532+
field.parent = fieldData[1]
533+
field.type = fieldData[2] % 128
534+
field.hidden = (bit32.rshift(fieldData[2], 7) == 1)
535+
field.name, i = fieldGetString(fieldData, 3, field.name)
536536
if functions[field.type+1].load then
537537
functions[field.type+1].load(field, fieldData, i)
538538
end
@@ -559,10 +559,11 @@ local function parseElrsInfoMessage(data)
559559
fieldChunk = 0
560560
return
561561
end
562-
badPkt = data[3]
563-
goodPkt = (data[4]*256) + data[5]
562+
local badPkt = data[3]
563+
local goodPkt = (data[4]*256) + data[5]
564+
goodBadPkt = tostring(badPkt) .. "/" .. tostring(goodPkt)
564565
elrsFlags = data[6]
565-
elrsFlagsInfo,offset = fieldGetString(data,7)
566+
elrsFlagsInfo = elrsFlags ~= 0 and fieldGetString(data, 7) or nil
566567
end
567568

568569
local function refreshNext()
@@ -623,7 +624,7 @@ local function lcd_title()
623624
lcd.drawFilledRectangle(0, 0, LCD_W, barHeight, CUSTOM_COLOR)
624625
lcd.setColor(CUSTOM_COLOR, BLACK)
625626
lcd.drawText(textXoffset+1, 4, title, CUSTOM_COLOR)
626-
lcd.drawText(LCD_W-3, 4, tostring(badPkt) .. "/" .. tostring(goodPkt), RIGHT + BOLD + CUSTOM_COLOR)
627+
lcd.drawText(LCD_W-3, 4, goodBadPkt, RIGHT + BOLD + CUSTOM_COLOR)
627628
-- progress bar
628629
if allParamsLoaded ~= 1 and fields_count > 0 then
629630
local barW = (COL2-4)*fieldId/fields_count
@@ -637,7 +638,7 @@ local function lcd_title()
637638
local barHeight = 9
638639

639640
lcd.clear()
640-
lcd.drawText(LCD_W, 1, tostring(badPkt) .. "/" .. tostring(goodPkt), RIGHT)
641+
lcd.drawText(LCD_W, 1, goodBadPkt, RIGHT)
641642
-- keep the title this way to keep the script from error when module is not set correctly
642643
if allParamsLoaded ~= 1 and fields_count > 0 then
643644
lcd.drawFilledRectangle(COL2, 0, LCD_W, barHeight, GREY_DEFAULT)
@@ -648,7 +649,7 @@ local function lcd_title()
648649
end
649650
end
650651
end
651-
652+
652653

653654
local function lcd_warn()
654655
lcd.drawText(textSize*3,textSize*2,tostring(elrsFlags).." : "..elrsFlagsInfo,0)
@@ -728,7 +729,7 @@ local function runDevicePage(event)
728729
handleDevicePageEvent(event)
729730

730731
lcd_title()
731-
732+
732733
if #devices > 1 then -- show other device folder
733734
fields[fields_count+1].parent = 0
734735
end
@@ -792,7 +793,7 @@ local function runPopupPage(event)
792793
end
793794
return 0
794795
end
795-
796+
796797
local function setLCDvar()
797798
lcdIsColor = lcd.RGB ~= nil
798799
if LCD_W == 480 then
@@ -806,7 +807,7 @@ local function setLCDvar()
806807
COL2 = 110
807808
else
808809
COL2 = 70
809-
end
810+
end
810811
maxLineIndex = 6
811812
textXoffset = 0
812813
textYoffset = 3
@@ -820,7 +821,7 @@ local function setMock()
820821
if string.sub(rv, -5) ~= "-simu" then return end
821822
local mock = loadScript("mockup/elrsmock.lua")
822823
if mock == nil then return end
823-
fields, goodPkt = mock(), 500
824+
fields, goodBadPkt = mock(), "0/500"
824825
fields_count = #fields - 1
825826
fieldId = #fields - 3
826827
end

0 commit comments

Comments
 (0)