PDA

View Full Version : String Processing in Lua



johnp
August 9th, 2006, 10:33 PM
I am trying to write a control for a Russound ST-2 and I am a little stuck.

1. Russound's protocol is ridiculous (glad that's off my chest).
2. Incoming strings have to be in hex because of some various forms of special characters and bitwise operators that they employ here and there. I am sure many are familiar with that because I see some have played with the CAV units.
3. For some insane reason they have a limit on how many bits can be used in a byte and so they have this special invert byte "F1". If you see that you have to invert all the bits of the following byte, and then use the result to fold into the bit mask to find out if the message is a flash type and who sent it etc. then toss the F1 out becasue it has no real data.


A sample string follows:
F07D0079007D000002010102010100000100 14 00 20 F1 7E 1C 52657669766520557300000000000000002D

As you can see byte 22 is an "F1" invert byte so the next byte 7E has to be inverted before it can be interpreted / decoded.

My first question is can Lua hunt for a F1 in a string? If so can I then ask it to do a bitwise inversion on the next byte? If so can someone give me a clue?

My next question is that bytes 24 and following (excluding the last checksum byte) are actually ASCII coded hex. Is there a simple way to convert a hex string to ASCII or do I have to use a lookup table?

Thanks as always.

Mark F
August 10th, 2006, 10:03 AM
You are in the G3.3 forum so I'll assume you are using that product. :)

Repeat after me: "The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend. The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend. The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend." :D

Finding "F1" should be doable with strfind. Once found, use tonumber on the next byte to change that into a number and use bxor(number, 255) to invert the bits in the number.

I'm not sure what you mean by "ASCII coded hex". Do you mean this is the hex representation of ASCII characters? If that is the case, you can use tonumber to turn each byte into a number and then use the format or strchar commands or a look-up table to convert the numbers to characters.

johnp
August 10th, 2006, 11:01 AM
Hi

I actually have read the manual front to back and found the strfind trick, (I have been through the string section numerous times) and I figured out how to toss it out after I find it by to a cat fo the part before and after the "F1" but the tonumber - bxor trick eluded me. I knew there had to be a way.

Since you were so helpful on that, do you have any ideas how I can iterate through a string byte by byte and convert convert the hex to ascii in a batch?

I am thinking that doing a strlength / 2 for a total byte count and then some type of while loop that decrements each time I process a byte, but I can't get my head around the whole thing.

Please forgive my ignorance, I am not a SW developer and it has been years since I wrote any meaningful scripts.

Thanks again for your help.

johnp
August 10th, 2006, 11:24 AM
You are in the G3.3 forum so I'll assume you are using that product. :)

Repeat after me: "The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend. The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend. The LUA 4.0 manual (http://www.lua.org/manual/4.0/) is my friend." :D

Finding "F1" should be doable with strfind. Once found, use tonumber on the next byte to change that into a number and use bxor(number, 255) to invert the bits in the number.

I'm not sure what you mean by "ASCII coded hex". Do you mean this is the hex representation of ASCII characters? If that is the case, you can use tonumber to turn each byte into a number and then use the format or strchar commands or a look-up table to convert the numbers to characters.


I can't seem to get tonumber to process hex digits.

I have a byte that is for example "7E"

if I do this:
print (tonumber (7E))

I get this:

error: malformed number;
last token read: `7E' at line 6 in string "?"

Is there a step I am missing?

Rob H
August 10th, 2006, 11:45 AM
That's partly because 7E isn't a string.

You should actually use

tonumber('7E', 16)

What I would do is to use gsub to preprocess the string to fix any F1<inverted> pairs i.e.


newstring = gsub(string, 'F1(..)',
function(iByte)
local num = bxor(tonumber(iByte, 16), 255) ;
return format('%.2X', num)
end)

johnp
August 10th, 2006, 04:35 PM
Ahh yes, as Mark said "The LUA 4.0 manual is my friend. The LUA 4.0 manual is my friend. The LUA 4.0 manual is my friend."

Forgot the base, don't I feel stupid.

Thanks also for the gsub trick, that works splendidly.

Best to you.

Rob H
August 10th, 2006, 04:43 PM
Once you've converted the inverted bytes you can use gsub to convert the hex characters to their ASCII equivalents.


gsub(string, '(%x%x)', function(value) return strchar(tonumber(value, 16)) end)

johnp
August 10th, 2006, 04:55 PM
Oh Man I owe you big now, that works perfectly!!!!!

I'll have to study it for an hour to figure out what it does. :-)

Thanks a million.

Rob H
August 10th, 2006, 05:02 PM
Not a problem - I'm quite pleased since I hadn't run that code.

It's actually pretty straightforward -

The pattern '(%x%x)' is a 'capture' (because of the parentheses) which matches pairs of hexadecimal characters.

The function just converts the pair of hex characters to a number and uses strchar (Lua 4's equivalent of Basic's CHR$) to convert that number back to a single character.

gsub is amazingly powerful.

johnp
August 10th, 2006, 05:08 PM
gsub is amazingly powerful.

I'll say it is, I was thinking of all sorts of complicated ways to solve this problem and gsub did it in 1 line. All I have to say is AWESOME!

Thanks again.

johnp
August 12th, 2006, 03:07 AM
Hi again,

I have one last thing to work through (I think).

I am having a problem with LuaCom trying to send nul characters oout the http port. Bascially if any string processed by the code below has a nul, it breaks LuaCom.



AsciiString = strsub(FixedString,47,80)
OutputString = gsub(AsciiString, '(%x%x)', function(value) return strchar(tonumber(value, 16)) end)


so lets say that the above Ascii string pulls out this:
"447220436861726C657320486179657300"
from the (FixedString).

The last "00" byte breaks LuaCom when processed by the gsub above. If I manually remove the 00 from the the string, it is passed along OK.

So my question is how can I use gsub to remove the nul characters, and yes I read the manual for about an hour to no avail. There is a warning about embedded 0s so that even made me more confused.

Thanks.

johnp
August 12th, 2006, 03:30 AM
This seems to work

newteststring = gsub(asciistring, '00', '')

Is there any problem with doing it this way? I guess I am most worried that it wouldn't always process on byte boundaries. For example, I wouldn't want

0x 3001

to get replaced with
0x 31

That would be a bad thing

Rob H
August 12th, 2006, 03:54 AM
That's where %z comes in - the manual isn't terribly clear about that

In your final string, before sending it out use


gsub(string, '%z', '')

Why are you send out the string to an http server?

johnp
August 12th, 2006, 11:37 AM
Hi Rob,

The http server is a third party system that displays information for me.

Thanks again for your help.