Hex Codes in DATA.TEXT
hodeyp
Posts: 104
I am writing a module to control a TagMcLaren DVD32R & AV192R via the 'TagTronic Bus' - this is a rs485 protocol built into all tag products.
I have no experience dealing with raw hex data and am struggling to work out how to best extract the data from the DATA.TEXT property.
When I switch on diagnostics for the rs485 port I see the following...
Line 31 :: String From [5001:4:1]-[$02$00$81$00$C1$80$02$01$FEx$89$E4$03] - 08:51:18
Message definition is...
Byte 1: STX
Byte 2&3: Sender Address
Byte 4&5: Target Address
Byte 6&7: Message Header
Byte 8&9: CRC
Byte 10: ETX
I have attempted to parse the string into a series of long variables i.e....
STACK_VAR LONG lSTX, lSender, lTarget, lHeader, lCRC,lETX
lSTX = GET_BUFFER_CHAR(DATA.TEXT)
lSender = GET_BUFFER_STRING(DATA.TEXT,2)
etc etc
Problem is that i receive the following error message in the diagnotics log...
(0011093491) GetString - Error 1 Tk=0x0001
I have read some of the amx tech docs & other postings in this forum and can't quite decide what i'm doing wrong or how to resolve it.
Should I be using longs to take in this data or another data type? I have also tried using the ATOL funtion to assign the variables but again I receive errors in the diagnostics log.
From what I understand the $ notation for hex is an AMX thing which means the string I see from the device is already going through some type of translation in the netlinx master. trouble is I cannot work out what its doing...
An issue i'm sure I will have once this is resolved is that the sender & target addresses need to further break down into 3 values, 1st 4 bits are unused, 2nd 6 bits is the group address & 3rd 6 bits is the device address. I am presuming I handle this by doing an 'X = Y << 4' ??
Swimming well out my depth here...help!!!
Regs, Phil
I have no experience dealing with raw hex data and am struggling to work out how to best extract the data from the DATA.TEXT property.
When I switch on diagnostics for the rs485 port I see the following...
Line 31 :: String From [5001:4:1]-[$02$00$81$00$C1$80$02$01$FEx$89$E4$03] - 08:51:18
Message definition is...
Byte 1: STX
Byte 2&3: Sender Address
Byte 4&5: Target Address
Byte 6&7: Message Header
Byte 8&9: CRC
Byte 10: ETX
I have attempted to parse the string into a series of long variables i.e....
STACK_VAR LONG lSTX, lSender, lTarget, lHeader, lCRC,lETX
lSTX = GET_BUFFER_CHAR(DATA.TEXT)
lSender = GET_BUFFER_STRING(DATA.TEXT,2)
etc etc
Problem is that i receive the following error message in the diagnotics log...
(0011093491) GetString - Error 1 Tk=0x0001
I have read some of the amx tech docs & other postings in this forum and can't quite decide what i'm doing wrong or how to resolve it.
Should I be using longs to take in this data or another data type? I have also tried using the ATOL funtion to assign the variables but again I receive errors in the diagnostics log.
From what I understand the $ notation for hex is an AMX thing which means the string I see from the device is already going through some type of translation in the netlinx master. trouble is I cannot work out what its doing...
An issue i'm sure I will have once this is resolved is that the sender & target addresses need to further break down into 3 values, 1st 4 bits are unused, 2nd 6 bits is the group address & 3rd 6 bits is the device address. I am presuming I handle this by doing an 'X = Y << 4' ??
Swimming well out my depth here...help!!!
Regs, Phil
0
Comments
First, you are on the right track and the fact that you are getting data from the device is half the battle!
Second, Netlinx is showing you the data as $02, $81, etc. since these represent non-printable Ascii characters.
Third, don't get hung up on HEX representation and how to store it in Netlinx. You have a data buffer which is essentially an array of CHARs (array of bytes). STX is $02 in hex but it is still stored in a single byte. The 0 represents the first 4-bits of the byte (0000) and 2 represents the last 4-bits in the byte (0010). Keep in mind that a byte can range in values from $00 to $FF so you can parse your HEX device data as a series of bytes or CHARs. Your device uses a HEX protocol which is byte oriented but many of the bytes are not printable Ascii characters. Many devices use Ascii oriented protocols and they are easier to read and interpret in log files and debug streams but at the end of the day, both techniques are byte oriented and you only need to interpret the data (parse and compare) accordingly.
So, to answer your question, move the HEX data returned from the device in DATA.TEXT to a CHAR array that is suitable in size to hold the data and then parse it accordingly. You can check for specific values by doing comparisons between values in the buffer and a specific HEX value, for example: You may even want to code your DATA_EVENT handler [STRING subevent] to look for the ETX in the data stream before you move the data from the buffer to begin parsing. You could do something like: You can also get more sophisticated by using COMPARE_STRING to examine the buffer for a sequence of HEX values using the Netlinx concatenation operator: As for breaking apart HEX values (examining bit patterns within a byte), using shift and masking operations as you noted is a way to do it. It is not the only way depending on the range of values you might get back from a device but it is certainly one of the better ways to accomplish what you are trying to do.
Hope this helps --
Reese
First of all, DATA.TEXT is transient. Chances are you can fully process whatever comes in before a new DATA_EVENT is generated, but once that happens, it's gone and replaced with the new stuff. What you should do is create a large CHAR array and use CREATE_BUFFER in DEFINE_START to link your port to that array. You can then forget about DATA.TEXT - all your data will be in the array. You can run a test like Reese described to look for your ETX character in the array to determine if it needs processing. You can put that test in mainline, or trigger it on the STRING handler of your EVENT.
I would personally create a smaller CHAR array to hold each packet at this point, and use something like sPacket = REMOVE_STING(sBigBuffer, "$03", 1) to populate it. You can then break out your elements into your target variables:
sTemp = MID_STRING(sPacket, 2, 2) ;
ISENDER = (ATOL("sTemp[1]") * 16) + ATOL("sTemp[2]") ;
The ATOL function takes care of converting to your target LONG. Depending on the form that address takes in HEX, you might not be able to do a direct extraction like in my example - it assumes a two-digit hex value, and not some ASCII representation. You may have to play around with the conversions. Like Reese said, don't get too hung up on the fact it's hex - a single character is a single hex didgit, and a string is just an array of them. So all your string functions can be used to manipulate them.
Notice every time I use a string function on a single character I enclose it in double quotes. This is necessary. Sometimes you will get a compiler error if you don't do this, but a lot of the time, it just plain misinterprets the data. Think of it as a type cast - those functions expect a string, and if your single character needs to be treated as a string of length one, so be it.
However, the protocol has a 2 byte value that needs to be parsed to return 3 values. The first 4 bits are reserved for future functionality, the other 2 groups of 6 bits are for group & device addresses. This gives a possible 63 groups & 63 devices and I need to know what these are to send messages to the correct device. I have tried using the LSHIFT function to remove the bits sequentially and convert to an integer value but have hit a stumbling block as the LSHIFT function only works on integers. Is it possible to combine the 2 hex char values into a single integer to do the bitwise stuff?
You'll have to excuse my terminology if its incorrect, I am very much a novice at low level byte & bit manipulation!!
An example of the address is "$01,$81" which by my calculations equate to a group address of 6 and a device address of 1 (bits 5-10 = 000110 & bits 11-16 = 000001)
Any help here would be very much appreciated!!
My TimeSync (the basis for i!-TimeManager) project does significant bitwise manipulation due to the SNTP protocol. I'd suggest you take a look at that and, if you have further questions, post them.
Here's a link where you can download the sources:
http://cvs.sourceforge.net/viewcvs.py/netlinx-modules/NetLinx-Modules/TimeSync/
Hope this helps,
-- Jeff
sTemp = MID_STRING(sPacket, 2, 2) ;
ISENDER = (ATOI("sTemp[1]") * $100) + ATOI("sTemp[2]") ;
If sTemp = "$1,$81", then ISENDER will be $185, or 110000001 in binary. You can do your bitwise operations from there.
Now that you are closer to that problem...
To have an integer that carries the group address, you want the 6 bits to be the last 6bits of an 8 bits integer...
So you want to make sure the 4 unused bits are 0. You can do that by "and-ing" 0x0F to the first byte above. Then shift group by two places Then add to that the 2 remaining bits, shifted so that they are in the right place... Voila. You can do it all in one shot, so that: For the device address it is simpler, you just need to mask the first 2 bits of B2... HTH
Fred
My last question (I promise!) - there are 2 types of message the bus generates, one is a fixed length 10byte message - all is working ok here now. The other message is variable length with bytes 8&9 detailing byte length for the variable length message (bytes 10 to 'n').
Byte 9 is actually the logical inverse of byte 8 as a form of error checking. I have this working ok and am receiving 100% success rate on checking.
Now for the problem...
The length field is again hex, the contoller is not extracting the correct number and instead returning an error about invalid conversion.
e.g. for a data length of 2 bytes the hex being returned is $02. From what I can see the code is trying to convert this into the ascii equivalent to determine the number so is in fact returning the ASCII 'STX' value. I have played about with the various HEXTOI, ATOI and similar functions but all seem to return the same result, the ascii representation of $02.
I'm not sure if i'm being a bit thick here but I can't seem to find a way of making it return the correct data
It's the same number no matter how you look at it, only in binary would it look different (10). It sounds to me like it is doing the right thing; trying to display the ASCII character is just a display issue, not a value issue. What line is generating the error? Heh, and what are the lines adjacent? The Studio compiler often highlights the wrong line for an error.
Length = GET_BUFFER_STRING(TagTronicBuffer,2)
IF(Length[1] BXOR Length[2] = $FF)
{
DataBytes = GET_BUFFER_STRING(TagTronicBuffer,Length[1])
SEND_STRING 0,"'DataBytes:',DataBytes"
}
the code compiles ok but i get an error when I enable diagnostics and the SEND_STRING returns [DataBytes:]. If it is converting is it not looking for hex $32?
SEND_STRING 0,"'DataBytes:', ITOA(DataBytes)"
should give you "DataBytes:2"...
HTH
Fred