@@ -296,9 +296,11 @@ local function encodeParameterEntry(device, param, _chunk, destAddr)
296296 end
297297 end
298298 data [# data + 1 ] = 0xFF -- terminator
299- elseif t == CRSF .INFO or t == CRSF .STRING then
300- -- INFO (read-only) and STRING (editable) both encode as null-terminated string
299+ elseif t == CRSF .INFO then
301300 appendString (data , param .value or " " )
301+ elseif t == CRSF .STRING then
302+ appendString (data , param .value or " " )
303+ data [# data + 1 ] = param .maxlen or 32
302304 elseif t == CRSF .UINT8 then
303305 -- value, min, max (1 byte each)
304306 data [# data + 1 ] = param .value or 0
@@ -381,7 +383,7 @@ local txDevice = {
381383 serialNo = CRSF .ELRS_SERIAL_ID ,
382384 hwVer = 0 ,
383385 swVer = 0x00030500 , -- 3.5.0
384- fieldCount = 21 , -- total parameter count
386+ fieldCount = 23 , -- total parameter count
385387 params = {
386388 {
387389 id = 1 ,
@@ -533,11 +535,36 @@ local txDevice = {
533535 info = " " ,
534536 },
535537
538+ -- Editable string field
539+ {
540+ id = 20 ,
541+ parent = 0 ,
542+ type = CRSF .STRING ,
543+ name = " Bind Phrase" ,
544+ value = " default" ,
545+ maxlen = 16 ,
546+ },
547+
548+ -- Float field (scaled integer with precision)
549+ {
550+ id = 21 ,
551+ parent = 0 ,
552+ type = CRSF .FLOAT ,
553+ name = " Freq Offset" ,
554+ value = 0 ,
555+ min = - 5000 ,
556+ max = 5000 ,
557+ default = 0 ,
558+ prec = 2 ,
559+ step = 1 ,
560+ units = " kHz" ,
561+ },
562+
536563 -- Bad/Good (hidden from ELRS Lua, visible to other UIs)
537- { id = 20 , parent = 0 , type = CRSF .INFO , name = " Bad/Good" , value = " 0/250" , hidden = true },
564+ { id = 22 , parent = 0 , type = CRSF .INFO , name = " Bad/Good" , value = " 0/250" , hidden = true },
538565
539566 -- Version + regulatory domain (name = version+domain, value = commit hash)
540- { id = 21 , parent = 0 , type = CRSF .INFO , name = " 3.5.0 ISM2G4" , value = " 825ed8" },
567+ { id = 23 , parent = 0 , type = CRSF .INFO , name = " 3.5.0 ISM2G4" , value = " 825ed8" },
541568 },
542569}
543570
@@ -1100,9 +1127,33 @@ local function mockPush(command, data)
11001127 local destAddr = data [2 ] or CRSF .ADDRESS_RADIO_TRANSMITTER
11011128 queuePush (CRSF .FRAMETYPE_PARAMETER_SETTINGS_ENTRY , encodeParameterEntry (device , param , 0 , destAddr ))
11021129 else
1103- -- Value write: update the stored value immediately (matches
1104- -- firmware config.Set*() which stores in RAM right away).
1105- param .value = writeValue
1130+ -- Value write: decode based on field type
1131+ if t == CRSF .STRING then
1132+ local chars = {}
1133+ local i = 4
1134+ while data [i ] and data [i ] ~= 0 do
1135+ chars [# chars + 1 ] = data [i ]
1136+ i = i + 1
1137+ end
1138+ param .value = (# chars > 0 ) and string.char (table.unpack (chars )) or " "
1139+ elseif t == CRSF .FLOAT then
1140+ local v = bit32.lshift (data [4 ] or 0 , 24 )
1141+ + bit32.lshift (data [5 ] or 0 , 16 )
1142+ + bit32.lshift (data [6 ] or 0 , 8 )
1143+ + (data [7 ] or 0 )
1144+ if v >= 0x80000000 then
1145+ v = v - 0x100000000
1146+ end
1147+ param .value = v
1148+ elseif t == CRSF .UINT16 or t == CRSF .INT16 then
1149+ local v = bit32.lshift (data [4 ] or 0 , 8 ) + (data [5 ] or 0 )
1150+ if t == CRSF .INT16 and v >= 0x8000 then
1151+ v = v - 0x10000
1152+ end
1153+ param .value = v
1154+ else
1155+ param .value = writeValue
1156+ end
11061157 -- Defer folder name and bandwidth updates to the next poll cycle.
11071158 -- Real firmware runs updateFolderNames() in the event loop, not
11081159 -- in the PARAMETER_WRITE handler. No auto-send of parent folder
0 commit comments