Android Question RegEx on byte arrays

Didier9

Well-Known Member
Licensed User
Longtime User
I am parsing byte arrays that contain a number of binary encoded messages (the whole 0-255 range) and I need to find start and end of messages and eliminate some byte stuffing. The data comes through WiFi and I have to process it as it comes. At the other end of the WiFi link is a serial device that sends data at 9600 bauds, so the data rate is not very high (probably 300-600 bytes/sec average, but the longer the messages, the less time I have to process them)

Doing it character by character with a for() loop is actually not fast enough to run on an inexpensive tablet (runs well on a Moto-X 4 and very well on a Pixel 2 but not well at all on a 5 year old XT1096 phone or the Fire tablet).

I have tried to cast the data to a string and use string matching and IndexOf() but that does not work, I suspect that the binary data containing zeros messes with strings that are normally null-terminated.

I should mention that after the messages are split, they still need to be decoded and displayed and at the moment, that takes about as long as the message splitting itself even though I am just putting text into labels (no fancy graphics).

Interestingly, the same algorithm runs very well in C on a 12 MHz 8 bit microcontroller driving an LCD :)

While for this app I could live with the requirement for a relatively modern device, I would like to explore a little bit for better ways to do it and
I thought regular expressions would probably help but apparently the RegEx.Matcher does not like binary data.

Any suggestion appreciated.
 

emexes

Expert
Licensed User
apparently the RegEx.Matcher does not like binary data
Lol.

Any suggestion appreciated.
Could you post a few sample packets? Annotations would be a bonus, eg, which bytes are lengths, checkvalues, etc.

Also, what does your receive routine look like, eg, do you receive one byte each call, or a block of up to say 32 bytes, and how are the messages split across blocks, eg, can one block contain the end of one message and the start of another?
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
The protocol is TSIP, Trimble Standard Interface Protocol:
http://www2.etown.edu/wunderbot/DOWNLOAD/AgGPS114/TSIP Reference Manual - Rev C.pdf

In short, messages start with DLE (0x10) followed by anything other than ETX (0x03) followed by a variable length binary data packet and end with DLE-ETX. Since data can include DLE and ETX, any DLE in the data payload is stuffed (DLE-DLE) so an actual end of message is ETX preceded by an odd number of DLEs. There is no checksum or byte count or parity bit.

It is easier to unequivocally detect an end of message since the payload can include DLE followed by not-ETX. The first byte (or two) after the start of message are used to identify the type of data in the message (message ID), so after a message has been isolated, it goes to a second routine that decodes the content based on the message ID.

I do not have the message handling code handy at the moment but I can post it tonight.

The messages come out of a timing GPS receiver's UART at 9600 Bauds and are fed into a serial-WiFi module. The WiFi module looks for a 20mS break in transmission and sends what's in its buffer then so usually all the WiFi packets start with DLE<message ID>, which could simplify decoding quite a bit even though at the moment I do not rely on that to find a message's beginning.

Each packet typically contains 3-6 messages (out of probably over 100 possible message types, I have not counted) but there is no hard limit on the number of messages other than you can only send so much data in one second. The user specifies which messages should be sent and the GPS receiver schedules them as it wants. Not all messages are sent every second, but some are.

Since the receiver sends a new set of packets every second, it's not the end of the world is we occasionally miss one, but the first message in each packet is the one with date/time info which is always sent so that one I do not want to miss. Some messages are only sent when the content has changed, so missing one of those could be an issue.

My routine is designed to deal with fragmentation but on my local network, I have not seen evidence of fragmentation yet.

This is intended as a monitoring app, not a mission critical application, but I am interested in looking at improving the byte manipulation code I am using.
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
so an actual end of message is ETX preceded by an odd number of DLEs
My initial reaction to this was "that's charming, who came up with that brilliant idea for a marker?" but after I read the paragraph again more thoroughly (and twice), it made sense. But it's still kinda funny.

:)
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Well, it's conceptually simple but I have implemented lots of binary protocols and let's just say I am not impressed. It helps that there is a lot of redundancy, that most of the packets can be lost without earth shattering consequences and that the overall data rate is very low.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Here is the routine receiving the packets and splitting them into messages.
I log the time at multiple points to see what's taking the longest.

B4X:
Sub NewData( buffer() As Byte )
    Dim in_ptr, out_ptr, msg_start As Int, end_found As Boolean=True
    Dim t As Long
   
    t = DateTime.now
    Log( "Entering NewData() " & DateTime.Time( DateTime.Now ) )

    ' ***TEST
    If DebugCount = 2 Then
        in_ptr = 0
    End If

    ' the following allows for segments of messages left in the RxBuffer even though I have seen no evidence of that on my network
    ' calculate the length of the new buffer big enough to receive the new packet and what's left of the last packet.
    RxBufferLen = RxBufferLen + buffer.Length
    ' create the new buffer
    Dim NewBuffer( RxBufferLen ) As Byte
    ' copy previous potentially unfinished buffer to it
    bc.ArrayCopy( RxBuffer, 0, NewBuffer, 0, RxBuffer.Length )
    ' add the just received packet to it
    bc.ArrayCopy( buffer, 0, NewBuffer, RxBuffer.Length, buffer.Length )

    ' process all the complete messages in the RxBuffer
    ' (here "end_found" means we found the end of a message, not that we have reached the end of the RxBuffer)
    Do While end_found = True
        Log( "Time in 1 NewData() " & (DateTime.Now - t) & " NewBuffer.Length: " & NewBuffer.Length )
        ' create a buffer for one message
        Dim msg_buf( RxBufferLen ) As Byte ' worst case the entire buffer is a single message

        ' pick the first complete message, put it in msg_buf and remove it from the RxBuffer
        msg_start = -1
        end_found = False
        out_ptr = 0
        ' we look ahead by one so we need to stop one short of the end
        For in_ptr=0 To NewBuffer.Length-2
            If NewBuffer(in_ptr) = 0x10 And NewBuffer(in_ptr+1) <> 0x03 And msg_start = -1 Then
                msg_start = in_ptr
            End If
            If msg_start > -1 Then
                If NewBuffer(in_ptr) = DLE And NewBuffer(in_ptr+1) = DLE Then
                    in_ptr = in_ptr+1
                    Continue
                End If
                msg_buf(out_ptr) = NewBuffer(in_ptr)
                If in_ptr > 2 Then
                    If NewBuffer(in_ptr-2) <> DLE And NewBuffer(in_ptr-1) = DLE And NewBuffer(in_ptr) = ETX Then
                        end_found = True
                        Exit
                    End If
                End If
                out_ptr = out_ptr + 1
            End If
        Next
        ' copy the last byte, typically ETX
        msg_buf(out_ptr) = NewBuffer(in_ptr)
       
        If msg_start > -1 Then
            ' we found a complete message, process it
            Log( "Time in 2 NewData() " & (DateTime.Now - t) )
            Dim out_buf(out_ptr+1) As Byte
            bc.ArrayCopy( msg_buf, 0, out_buf, 0, out_ptr+1 )
            Log( "Time in 3 NewData() " & (DateTime.Now - t) & " Processing message " & ToHex( out_buf(1)) & ToHex( out_buf(2)) & " Length: " & out_buf.Length )
            ProcessMessage( out_buf )
           
            Log( "Time in 4 NewData() " & (DateTime.Now - t) )

            ' remove the message just processed from the RxBuffer
            RxBufferLen = RxBufferLen - in_ptr - 1
            'Dim RxBuffer( RxBufferLen ) As Byte
            Dim tmpBuffer( RxBufferLen ) As Byte
            bc.ArrayCopy( NewBuffer, in_ptr+1, tmpBuffer, 0, RxBufferLen )
            Dim NewBuffer( RxBufferLen ) As Byte
            bc.ArrayCopy( tmpBuffer, 0, NewBuffer, 0, RxBufferLen )
        End If
    Loop
    Log( "Time in 5 NewData() " & (DateTime.Now - t) )

    ' if NewBuffer not empty, copy back to RxBuffer
    Dim RxBuffer( RxBufferLen ) As Byte
    If NewBuffer.Length > 0 Then
        bc.ArrayCopy( NewBuffer, 0, RxBuffer, 0, RxBufferLen )  
    End If

    ' ***TEST
    DebugCount = DebugCount + 1

    Log( "Time in 6 NewData() " & (DateTime.Now - t) )

End Sub ' NewData()
and here is an example log file with the slowest device I have (a pre-paid Alcatel phone that costs $29.95).
It is useful to illustrate what takes time. On the Pixel 2, the longest packet takes 6 mS in total.
This spans the processing of a single packet composed of 4 messages. Message 0x8F 0xAC is the longest and takes the longest to isolate.
ProcessMessage() breaks the messages into variables and display then into labels. This part is pretty fast.
B4X:
Entering NewData() 17:23:59
Time in 1 NewData() 4 NewBuffer.Length: 183
Time in 2 NewData() 179 --------> (179-4) = 175mS
Time in 3 NewData() 179 Processing message 0x8F 0xAB  Length: 20
Time in 4 NewData() 189
New NewBuffer.Length: 161
Time in 1 NewData() 190 NewBuffer.Length: 161
Time in 2 NewData() 402 --------> (402-190) = 212mS
Time in 3 NewData() 403 Processing message 0x6D 0x7D  Length: 27
Time in 4 NewData() 410
New NewBuffer.Length: 132
Time in 1 NewData() 411 NewBuffer.Length: 132
Time in 2 NewData() 1079 ------> (1079 - 411) = 668mS
Time in 3 NewData() 1080 Processing message 0x8F 0xAC  Length: 72
Time in 4 NewData() 1094
New NewBuffer.Length: 60
Time in 1 NewData() 1095 NewBuffer.Length: 60
Time in 2 NewData() 1560 -------> (1560-1095) = 465mS for 56 characters
Time in 3 NewData() 1561 Processing message 0x8F 0xA7  Length: 56
Time in 4 NewData() 1570
New NewBuffer.Length: 0
Time in 5 NewData() 1571
Time in 6 NewData() 1588
Clearly what takes the longest is the For in_ptr=0 To NewBuffer.Length-2 loop but really all it does is iterate through the buffer and do simple byte-wise comparisons. The longest message is 72 bytes long. Hard to imagine it takes 600mS to process it.

As you can see, since a new packet arrives every second, nothing good happens if it takes 1.6 second to process one packet.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I just found a major contributor to speed variability.
If I simply compile and run, the Alcatel phone is pretty fast. If I use the hot code update feature in debug mode, it crawls to a stop (see timing above).
If I simply stop the debug session and restart, it is again very fast (longest message takes 15mS).
The older Moto-X 2 doesn't seem to be as affected by hot debugging even though it is noticeable, the Pixel 2 and Moto-X 4 not at all.
 
Upvote 0

emexes

Expert
Licensed User
Sorry, I got distracted by school run etc. I thought about the issue whilst driving though, figured it must be that Strings were being used, or some other repeated memory allocation-deallocation that might occasionally be forcing a garbage collection. I also worked out that my usual packet receive-and-assemble approach could be easily massaged to cope with the escaped-DLE situation, so I'll give that a burl here, see what sort of times I get (in B4J, but... good enough for purpose, should port straight across).

The longest message is 72 bytes long. Hard to imagine it takes 600mS to process it.
Agreed :-/

As you can see, since a new packet arrives every second, nothing good happens if it takes 1.6 second to process one packet.
Lol.
 
Upvote 0

emexes

Expert
Licensed User
I just found a major contributor to speed variability.
Big thumbs-up to this.

I'll try the variation of my usual algorithm anyway, because it comes at the task from a different angle and so perhaps might still be a useful epiphany trigger.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
It also looks like my routine on occasion is missing some of the DLE-DLE pairs and the data payload is shifted by one.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I uploaded a short binary file with a few seconds worth of traffic. The file is zipped and has .hex extension but it's not in hex format.
 

Attachments

  • TBMon.2019Nov26_1900.zip
    2.6 KB · Views: 283
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I am working to be able to read it instead of network packets. Should be easier to track bugs in the message handler, and simulate fragmentation.
 
Upvote 0

emexes

Expert
Licensed User
I uploaded a short binary file with a few seconds worth of traffic. The file is zipped and has .hex extension but it's not in hex format.
Hey, I was just about to use your earlier sample data but this should be much better.

It also looks like my routine on occasion is missing some of the DLE-DLE pairs and the data payload is shifted by one.
Yeah, I ran into a couple of ambiguities too in that area, eg:

- how to interpret a packet that starts with two DLE DLE (since that is a match for the starting sequence definition of DLE followed by not-ETX)
- how to interpret a DLE ETX that is not within a packet (or conversely: how to code a packet with first data byte = ETX)

Presumably these edge cases are covered in the spec but I figured I'll get it working 99% first and delve down those dark little alleys later ;-)
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
- how to interpret a packet that starts with two DLE DLE (since that is a match for the starting sequence definition of DLE followed by not-ETX)
At the moment, DLE is not used as a message ID. I assume it would be a bad idea but the spec does not say. But if the first data packet were DLE, it would be stuffed DLE-DLE.
- how to interpret a DLE ETX that is not within a packet (or conversely: how to code a packet with first data byte = ETX)
Since DLE is not used as message ID, there should be no issue if the first data byte is ETX.
 
Upvote 0

emexes

Expert
Licensed User
Works great. B4J in debug mode chokes on code size of embedded test data, hence the #IF .. #END IF.

Minor point: the HandleMultipleBytes and HandleOneByte routines are "inside out" from an efficiency point-of-view, since your incoming data is received in groups rather that one-by-one. But it is simpler to understand the way it currently is, so I have left well-enough alone.

B4X:
Sub Process_Globals
   
    Private DLE As Byte = 0x10
    Private ETX As Byte = 0x03
   
    Private Packet(345) As Byte    'adjust to suit longest packet (or reduce to 68 to fail with test data)
    Private PacketSize As Int
   
    Private PacketState As Int = 0
        '0 = idle, waiting for initial DLE
        '1 = got initial DLE, waiting for non-DLE
        '2 = in packet, waiting for data byte or DLE
        '3 = in packet, got DLE, waiting for DLE or ETX

End Sub

Sub AppStart (Form1 As Form, Args() As String)
   
    Dim StartTime As Long = DateTime.Now
   
    Test
   
    Dim EndTime As Long = DateTime.Now
    Log(EndTime - StartTime)
   
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub HandleMultipleBytes(BA() As Byte)
   
    For I = 0 To BA.Length - 1
        HandleOneByte(BA(I))
    Next
   
End Sub

Sub HandleOneByte(B As Byte)
   
    Select Case PacketState
        Case 0:
            If B = DLE Then
                PacketState = 1
            Else
                'noise on line
                Log("wtf 58") 
            End If
       
        Case 1:
            If B = ETX Then
                'empty packet (but complete it and pass to packet handler anyway?)
                Log("wtf 64") 
               
                PacketSize = 0
                HandlePacket(PacketSize, Packet)
                PacketState = 0
            Else
                Packet(0) = B
                PacketSize = 1
                PacketState = 2    'start receiving data
            End If
           
        Case 2:
            If PacketSize < Packet.Length Then
                Packet(PacketSize) = B
            End If
            PacketSize = PacketSize + 1
           
            If B = DLE Then
                PacketState = 3
            End If
           
        Case 3:
            If B = DLE Then
                'no need to add to packet buffer - it is already there ;-)
                PacketState = 2
            else If B = ETX Then
                PacketSize = PacketSize - 1    'remove terminator DLE from packet
                HandlePacket(PacketSize, Packet)
                PacketState = 0
            Else
                'not sure if this byte is valid or not: it could be treated as
                '    - start-of-packet sequence (implemented here)
                '    - unnecessarily-escaped byte
                '    - error
                Log("wtf 98") 
               
                Packet(0) = B
                PacketSize = 1
                PacketState = 2
            End If
           
    End Select
   
End Sub

Sub HandlePacket(PktSize As Int, Pkt() As Byte)
   
    '''return    'disable logs for benchmarking
   
    Dim PacketText As String = "Length " & PktSize & " ="
    For I = 0 To PktSize - 1
        If I < Packet.Length Then
            PacketText = PacketText & " " & Bit.And(Pkt(I), 0xFF)
        Else
            PacketText = PacketText & " TOO LONG!!!"
            Log("wtf 117")
            Exit
        End If
    Next
    Log(PacketText)

End Sub

Sub Test()

    HandleMultipleBytes(Array As Byte(16,143,171,0,4,2,193,4,33,0,18,0,49,0,1,12,4,7,208,16,3,16,109,125,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,63))
    HandleMultipleBytes(Array As Byte(128,0,0,16,16,9,8,23,27,7,26,16,3,16,143,172))
    HandleMultipleBytes(Array As Byte(7,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,63,128,98,77,187,157,109,254,0,8,166,253,62,208,188,64))
    HandleMultipleBytes(Array As Byte(66))
    HandleMultipleBytes(Array As Byte(36,242,190,63,225,2,253,79,116,184,236,191,248,45,250))
    HandleMultipleBytes(Array As Byte(147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2))
    HandleMultipleBytes(Array As Byte(193,48,137,217,236,172,169,9,239,16))
    HandleMultipleBytes(Array As Byte(16,49,162,102,220,9,51,16,16,12,223,8,179,77,236,53,23,49,132,24,23,27,179,5))
    HandleMultipleBytes(Array As Byte(125,74,7,51,67,11,186,26,176,220,32,97,0,0,0,0,0,16,3,16,87))
    HandleMultipleBytes(Array As Byte(1,5,72,128,88,32,4,33,16,3,16,19,60,245,16,3,16,143,171,0,4,2,194,4,33,0,18))
    HandleMultipleBytes(Array As Byte(0,50,0,1,12,4,7,208,16,3))
    HandleMultipleBytes(Array As Byte(16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0))
    HandleMultipleBytes(Array As Byte(16,16,9,8,23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,63,134,229,222,188,145,115,59,0,8,166,252,62,208,187,0,66,36))
    HandleMultipleBytes(Array As Byte(242,160,63,225,2,253,79,116,184,236,191,248,45,250))
    HandleMultipleBytes(Array As Byte(147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2))
    HandleMultipleBytes(Array As Byte(194,48,144,216,118,173,156))
    HandleMultipleBytes(Array As Byte(45,6,16,16,49,156,109,222,9,51,15,242,239,8,179,78,125,25,23,49,134,202,65,27,179,5,51,70,7))
    HandleMultipleBytes(Array As Byte(51,67,5,114,26,176,181,138,153,0,0,0,0,0,16,3,16))
    HandleMultipleBytes(Array As Byte(19,60,246,16,3,16,143,171,0,4,2,195,4,33,0,18,0,51,0,1,12,4,7,208,16,3,16,109,125,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0))
#IF 0
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,63,128,0,0,16,16,9))
    HandleMultipleBytes(Array As Byte(8,23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,144,176,71,189))
    HandleMultipleBytes(Array As Byte(73,229,124,0,8,166))
    HandleMultipleBytes(Array As Byte(252,62,208,187,0,66,36,242,133,63,225,2,253,79,116,184,236,191,248,45,250))
    HandleMultipleBytes(Array As Byte(147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16))
    HandleMultipleBytes(Array As Byte(3,16,143,167,0,0,4,2,195,48,155,91))
    HandleMultipleBytes(Array As Byte(178,174,88))
    HandleMultipleBytes(Array As Byte(200,222,16,16,49,155,98,13,9,51,15,171,250,8,179,79,239,78,23,49,136,214,4,27,179))
    HandleMultipleBytes(Array As Byte(4,151,102,7,51,67,190,29,26,176,136,118,87))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,16,3,16,69,3,0,6,27,2))
    HandleMultipleBytes(Array As Byte(10,2,11,14,1,16,3,16,143,65,0,0,0,189,228,19,2,11,6,20,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,143,66,0,30,0,0,0,189,228,19,0,0,187,179))
    HandleMultipleBytes(Array As Byte(0,16,16,0,0,228,19,16,3,16,19,28,1,16))
    HandleMultipleBytes(Array As Byte(3,16,19))
    HandleMultipleBytes(Array As Byte(28,3,16,3,16,19,60,247,16,3,16,143,171,0,4,2,196,4,33,0,18,0,52,0,1,12,4,7,208))
    HandleMultipleBytes(Array As Byte(16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0))
    HandleMultipleBytes(Array As Byte(0,16,16,9,8,23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,63,159,239))
    HandleMultipleBytes(Array As Byte(139,59,176,89,155,0,8,166,252,62,208,187,0,66,36,242,109,63,225,2,253,79,116,184))
    HandleMultipleBytes(Array As Byte(236,191,248,45,250,147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167))
    HandleMultipleBytes(Array As Byte(0,0,4,2,196,48,171,186,203,44,189,90,185,16))
    HandleMultipleBytes(Array As Byte(16,49,148,78,103,9))
    HandleMultipleBytes(Array As Byte(51,15,77,85,8,179,80,219))
    HandleMultipleBytes(Array As Byte(211,23,49,139,133,59,27,179,3,246,169,7,51,68,183,247,26,176,43,37,77,0,0,0,0,0,16))
    HandleMultipleBytes(Array As Byte(3,16,187,0,7,0,4,2,62,50,184,194,64,128,0,0))
    HandleMultipleBytes(Array As Byte(65,0,0,0,64,192,0,0,30,1,0,0,1,0,255,255,255,255,255,255,255,255,255,255,255))
    HandleMultipleBytes(Array As Byte(255,255,16,3,16,19,60,248,16,3,16,143,171,0,4,2,197,4,33,0,18,0,53,0,1,12))
    HandleMultipleBytes(Array As Byte(4,7,208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8))
    HandleMultipleBytes(Array As Byte(23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,63,172,62,137,187,175,4,230,0,8,166,252,62,208,187,0,66,36,243,16,16,63))
    HandleMultipleBytes(Array As Byte(225,2,253,79,116,184,236))
    HandleMultipleBytes(Array As Byte(191,248,45,250,147,210,67,237,192))
    HandleMultipleBytes(Array As Byte(50,42,96,52,172,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,197,48,184,242,37,172,187,236))
    HandleMultipleBytes(Array As Byte(229,16,16,49,144,230,187,9,51,15,79,123,8,179,80,192,243,23,49,144,164,89,27,179,2))
    HandleMultipleBytes(Array As Byte(252,86))
    HandleMultipleBytes(Array As Byte(7,51,69,247,188,26,171,132,83,39,0,0,0,0,0,16))
    HandleMultipleBytes(Array As Byte(3,16,143,162,0,16,3,16,19,60,249,16))
    HandleMultipleBytes(Array As Byte(3,16))
    HandleMultipleBytes(Array As Byte(143,171,0,4))
    HandleMultipleBytes(Array As Byte(2,198,4,33,0,18,0,54))
    HandleMultipleBytes(Array As Byte(0,1,12,4,7,208,16,3,16,109,125,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,63,128,0,0))
    HandleMultipleBytes(Array As Byte(16))
    HandleMultipleBytes(Array As Byte(16,9,8,23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,63,184,103,214))
    HandleMultipleBytes(Array As Byte(188,157,61,214,0,8,166,252,62,208,187,0,66))
    HandleMultipleBytes(Array As Byte(36,242,234,63,225,2,253))
    HandleMultipleBytes(Array As Byte(79,116,184,236,191,248,45,250,147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,1,16,3,16,143,167,0))
    HandleMultipleBytes(Array As Byte(0,4,2,198,48,198,1,7))
    HandleMultipleBytes(Array As Byte(173,168,214,59,16,16,49,139,41,100,9,51))
    HandleMultipleBytes(Array As Byte(14,122))
    HandleMultipleBytes(Array As Byte(25,8,179,80,196,180,23,49,142,125,136,27,179,1,166,33,7,51,71,211,105,26,47,154,40,171,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,19,142,78,16,3,16))
    HandleMultipleBytes(Array As Byte(19,60))
    HandleMultipleBytes(Array As Byte(250,16,3))
    HandleMultipleBytes(Array As Byte(16,143,171,0,4,2,199,4,33,0,18,0,55,0,1))
    HandleMultipleBytes(Array As Byte(12,4,7,208,16,3,16,109,125,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,63,128,0,0,16,16,9,8,23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,63,200,119,215,188,15,107,147,0,8,166,251,62,208,185))
    HandleMultipleBytes(Array As Byte(192,66,36,243,128,63,225,2,253,79,116,184,236,191,248,45,250,147))
    HandleMultipleBytes(Array As Byte(210,67))
    HandleMultipleBytes(Array As Byte(237))
    HandleMultipleBytes(Array As Byte(192,50,42,96))
    HandleMultipleBytes(Array As Byte(52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,199,48))
    HandleMultipleBytes(Array As Byte(215,64,66,173,25,255))
    HandleMultipleBytes(Array As Byte(13,16))
    HandleMultipleBytes(Array As Byte(16,49,129,168,146,9,51,14,224,220,8))
    HandleMultipleBytes(Array As Byte(179,80,103,179,23,49,139,220,135,27,179,0,154,71,7,51,73,119,233,26,47,218,136,56))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,16,3,16,143,74,1,2,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,67,150,0,0,16,3,16,143,161,0,16,3,16,19,60,251,16,3,16,143,171))
    HandleMultipleBytes(Array As Byte(0,4,2,200,4,33,0,18,0,56,0,1,12))
    HandleMultipleBytes(Array As Byte(4,7,208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128))
    HandleMultipleBytes(Array As Byte(0,0,16,16,9,8,23,27,7,26,16,3,16,143,172))
    HandleMultipleBytes(Array As Byte(7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,216,33,147,59,143,185))
    HandleMultipleBytes(Array As Byte(46,0,8,166,251,62,208,185,192,66,36,243,79))
    HandleMultipleBytes(Array As Byte(63,225,2))
    HandleMultipleBytes(Array As Byte(253,79,116))
    HandleMultipleBytes(Array As Byte(184))
    HandleMultipleBytes(Array As Byte(236,191,248,45,250,147,210,67,237,192,50,42,96))
    HandleMultipleBytes(Array As Byte(52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,200,48,232))
    HandleMultipleBytes(Array As Byte(17,174,44,154,82,96,16))
    HandleMultipleBytes(Array As Byte(16,49,129,31,117))
    HandleMultipleBytes(Array As Byte(9,51,15,194,25,8,179,80,99,79,23,49,136,52,73,27,178,254,208,134,7,51,74,145))
    HandleMultipleBytes(Array As Byte(173,26,48,72))
    HandleMultipleBytes(Array As Byte(0,169,0,0,0,0,0,16,3,16,143,169,1,1,0,0,7,208,0,0,0,0,16,3,16,19,60,252,16,3))
    HandleMultipleBytes(Array As Byte(16,143,171,0,4,2,201,4,33,0,18,0,57,0,1,12,4,7,208,16))
    HandleMultipleBytes(Array As Byte(3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27))
    HandleMultipleBytes(Array As Byte(7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,220,203))
    HandleMultipleBytes(Array As Byte(169,189,8,235,244,0,8,166,251,62,208,185,192,66,36))
    HandleMultipleBytes(Array As Byte(243,35,63,225,2,253))
    HandleMultipleBytes(Array As Byte(79,116,184,236))
    HandleMultipleBytes(Array As Byte(191,248,45))
    HandleMultipleBytes(Array As Byte(250,147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0))
    HandleMultipleBytes(Array As Byte(4,2,201,48,237,19,210,174,19,4,192,16,16,49,116,230,21,9,51,17,81,171))
    HandleMultipleBytes(Array As Byte(8,179,80,122))
    HandleMultipleBytes(Array As Byte(13,23,49,133,123,1,27,178,252,154,176,7,51,75,48,10,26,48,165,177,186,0,0,0,0,0,16))
    HandleMultipleBytes(Array As Byte(3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7))
    HandleMultipleBytes(Array As Byte(26,16,3,16,19))
    HandleMultipleBytes(Array As Byte(60,253,16,3,16,143,171,0,4,2,202,4,33,0,18,0,58,0,1,12,4,7,208,16,3,16,109))
    HandleMultipleBytes(Array As Byte(125,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,63,128,0,0,16,16,9,8))
    HandleMultipleBytes(Array As Byte(23,27,7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,230,227,132,188,165))
    HandleMultipleBytes(Array As Byte(123,95,0,8,166,251,62,208,185,192,66,36,242,251,63,225,2,253,79))
    HandleMultipleBytes(Array As Byte(116,184,236,191,248,45,250,147,210,67,237,192,50,42,96))
    HandleMultipleBytes(Array As Byte(52,172,0,0,0,0,0,0,0,0,0,1,16,3,16))
    HandleMultipleBytes(Array As Byte(143,167,0,0,4))
    HandleMultipleBytes(Array As Byte(2,202,48,247,234,54,173,177,175,83,16,16,49,97,61,154,9,51,19,110))
    HandleMultipleBytes(Array As Byte(95,8,179,81,84,13,23,49,130,97,160,27,178,253,165,160,7,51,74,229,81,26,48,201,197))
    HandleMultipleBytes(Array As Byte(137,0,0,0,0,0,16,3,16,71,8,16,16,66,44,0,0,3,193,202,102,102,9,66))
    HandleMultipleBytes(Array As Byte(54,102,102,8,66,51,153,154,23,66,49,153,154,27,66,60,0,0,7,66,55,51,51,26,66,24,204,205))
    HandleMultipleBytes(Array As Byte(16,3,16,19,60,254,16,3,16,143,171,0))
    HandleMultipleBytes(Array As Byte(4,2))
    HandleMultipleBytes(Array As Byte(203,4,33,0,18,0,59,0,1))
    HandleMultipleBytes(Array As Byte(12,4,7,208,16,3,16,109,125,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,63,128,0,0))
    HandleMultipleBytes(Array As Byte(16,16,9))
    HandleMultipleBytes(Array As Byte(8,23,27,7,26,16,3))
    HandleMultipleBytes(Array As Byte(16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,34,255,188))
    HandleMultipleBytes(Array As Byte(50,220,118,0,8,166,250,62,208,184,128,66,36,242,215,63,225))
    HandleMultipleBytes(Array As Byte(2,253,79,116,184,236,191,248,45,250,147,210,67,237,192,50,42,96,52,172,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,1,16,3,16,143,167,0,0,4,2,203,49,9,149,243))
    HandleMultipleBytes(Array As Byte(173,64,12,252,16,16,49,77,28,75,9,51,22))
    HandleMultipleBytes(Array As Byte(36,138,8,179,80,131,231,23))
    HandleMultipleBytes(Array As Byte(49,129,83,45,27,178,252,121))
    HandleMultipleBytes(Array As Byte(180))
    HandleMultipleBytes(Array As Byte(7,51,75,63,62,26,48,192,18,70,0,0,0,0,0,16,3,16,89,3,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,16,3,16,89,6,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,19,60,255,16,3,16,143,171,0,4,2,204,4,33,0,18,0))
    HandleMultipleBytes(Array As Byte(0,1,1,12,4,7,208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16))
    HandleMultipleBytes(Array As Byte(9,8,23,27,7,26,16,3,16,143,172))
    HandleMultipleBytes(Array As Byte(7,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,64,6,189,26,188,30,209,242,0,8))
    HandleMultipleBytes(Array As Byte(166,250,62,208,184,128,66,36,242,183,63,225,2,253,79,116))
    HandleMultipleBytes(Array As Byte(184,236,191,248,45,250,147,210,67,237,192,50,42,96,52,172,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,1,16))
    HandleMultipleBytes(Array As Byte(3,16,143,167,0,0,4,2,204,49,16,16,172,176,173,42,136,35,16,16,49))
    HandleMultipleBytes(Array As Byte(63,129,135,9,51,24,85,158,8,179,78,211,185,23,49,135,86))
    HandleMultipleBytes(Array As Byte(228))
    HandleMultipleBytes(Array As Byte(27,178,251,36,182,7,51,76,88,196,26))
    HandleMultipleBytes(Array As Byte(48,214,74,60,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,16,3,16,143,21,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,0,65,88,84,166))
    HandleMultipleBytes(Array As Byte(64,0,0,0,63,123,107,144,241,254))
    HandleMultipleBytes(Array As Byte(143,2,16,3,16,143,171,0,4,2,205,4,33,0,18,0,1,1,1,12,4,7))
    HandleMultipleBytes(Array As Byte(208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0))
    HandleMultipleBytes(Array As Byte(16,16,9,8,23,27,7,26,16))
    HandleMultipleBytes(Array As Byte(3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,4,242,70))
    HandleMultipleBytes(Array As Byte(189,0,247,194,0,8,166))
    HandleMultipleBytes(Array As Byte(250,62,208,184,128,66,36,243,82,63,225,2,253,79,116,184,236,191,248,45,250,147,210,67,237,192,50,42,96,52))
    HandleMultipleBytes(Array As Byte(172,0,0,0,0,0,0,0,0,0,1,16,3,16))
    HandleMultipleBytes(Array As Byte(143,167,0,0,4,2,205,49,14,192,5))
    HandleMultipleBytes(Array As Byte(174,10,122,102,16,16,49))
    HandleMultipleBytes(Array As Byte(53,4,113,9,51,24,197,63,8,179,78,56,24,23,49,144,21,129,27,178,249,215,72,7,51,76,221,167))
    HandleMultipleBytes(Array As Byte(26,48,229,218,15,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,88,2,5,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,190,16,16,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,168,0,0,0,0,18,72,246,0))
    HandleMultipleBytes(Array As Byte(0,4,33,4,137,0,7,0,18,16,3,16,143,171))
    HandleMultipleBytes(Array As Byte(0,4,2,206,4,33,0,18,0,2,1))
    HandleMultipleBytes(Array As Byte(1,12,4,7,208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0))
    HandleMultipleBytes(Array As Byte(16,16,9,8,23,27,7,26,16,3,16))
    HandleMultipleBytes(Array As Byte(143,172,7,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,64,3,5,110,187,191,124,4,0,8,166,250,62))
    HandleMultipleBytes(Array As Byte(208,184,128,66,36,243,222,63,225,2,253,79,116,184,236,191,248,45,250))
    HandleMultipleBytes(Array As Byte(147))
    HandleMultipleBytes(Array As Byte(210,67))
    HandleMultipleBytes(Array As Byte(237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16))
    HandleMultipleBytes(Array As Byte(3,16,143,167,0,0,4,2,206,49))
    HandleMultipleBytes(Array As Byte(12,174,214,172,205,154,215,16,16,49))
    HandleMultipleBytes(Array As Byte(11,48,201,9,51,24,165,57,8,179,77,128,186,23,49,146,196,134,27,178,249,94,216))
    HandleMultipleBytes(Array As Byte(7,51,76,231,179,26,48))
    HandleMultipleBytes(Array As Byte(227,41,14,0,0,0,0,0,16,3,16,112,1,1,1,0,16,3,16,92,3))
    HandleMultipleBytes(Array As Byte(8,2,2,65,220,204,205,72,128))
    HandleMultipleBytes(Array As Byte(89,208,62,119,153,243,64,107,159,223,0,0,0,1,16,3,16,143,171,0,4))
    HandleMultipleBytes(Array As Byte(2,207,4,33,0,18,0,3,1,1,12,4))
    HandleMultipleBytes(Array As Byte(7,208,16,3,16,109,125,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27))
    HandleMultipleBytes(Array As Byte(7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,253,74,163))
    HandleMultipleBytes(Array As Byte(60,59,55,94,0,8,166,250,62,208,184,128,66,36,244,92,63,225,2,253,79,116,184,236,191,248,45,250,147,210))
    HandleMultipleBytes(Array As Byte(67,237,192,50,42,96,52,172,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,1,16,3,16,143,167,0,0))
    HandleMultipleBytes(Array As Byte(4,2))
    HandleMultipleBytes(Array As Byte(207,49,7,252,32,45,73,5,159,16,16,48,177,183,184,9,51,24))
    HandleMultipleBytes(Array As Byte(253,221))
    HandleMultipleBytes(Array As Byte(8,179,76,228,53,23,49,156,135,202,27,178,248,41,86,7,51,76,226,73,26,48,235,48,217,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,90,16,16,67,72,0,0,66,45,51,51,69,231,15,208,197,42,242,47,65,16,16,11,61))
    HandleMultipleBytes(Array As Byte(153,153,153,153,16,3,16,90,9,67,72,0,0,66,50,204,205,69,161,194,139,68,209,86,200))
    HandleMultipleBytes(Array As Byte(65,16,16,11,61,153,153,153,153))
    HandleMultipleBytes(Array As Byte(16,3,16,90,8,67,72,0,0,66,54,0,0,68,249,91,63,69,34,82,116,65,16,16,11,61,153))
    HandleMultipleBytes(Array As Byte(153,153,153,16,3,16,90,23,67,72,0))
    HandleMultipleBytes(Array As Byte(0,66,54,102,102,70,38,129,42,66,160,95,0,65,16,16,11,61,153,153))
    HandleMultipleBytes(Array As Byte(153,153,16,3,16,90,27,67,72,0,0))
    HandleMultipleBytes(Array As Byte(66,62,0,0,69,69,76,13,67,244,216,0,65))
    HandleMultipleBytes(Array As Byte(16,16,11,61,153,153,153,153,16,3,16,90,7,67,72,0,0,66,58,102))
    HandleMultipleBytes(Array As Byte(102,70,34,14,188,69,18,174,80,65,16,16,11,61,153,153,153,153,16,3,16,90))
    HandleMultipleBytes(Array As Byte(26,67,72,0,0,66,23,153,154,70,26,179,202))
    HandleMultipleBytes(Array As Byte(197,59,130,28,65,16,16,11,61,153,153,153,153,16,3,16,143))
    HandleMultipleBytes(Array As Byte(171,0,4,2,208,4,33,0))
    HandleMultipleBytes(Array As Byte(18,0,4,1,1,12,4,7,208,16,3,16,109,125,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7,26,16,3,16,143,172,7,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,63,239,137,239,188,99,135))
    HandleMultipleBytes(Array As Byte(45,0,8,166,251))
    HandleMultipleBytes(Array As Byte(62,208,185,192,66,36,244,205,63,225,2,253,79,116,184,236,191,248,45,250,147,210,67,237,192,50,42,96,52))
    HandleMultipleBytes(Array As Byte(172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,208,49,0,153,246))
    HandleMultipleBytes(Array As Byte(173,116,78,110,16,16,48,116,7,130,9,51,25,16,16,156,8,179,76,38,216,23,49,164,178,173))
    HandleMultipleBytes(Array As Byte(27,178,247,215,1,7,51,76))
    HandleMultipleBytes(Array As Byte(227,56,26,48,177,202,52,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,143,168,0,66,200,0,0,63))
    HandleMultipleBytes(Array As Byte(153,153,154,16))
    HandleMultipleBytes(Array As Byte(3,16,143,168,1,192,160,0,0,192,160,0,0,64))
    HandleMultipleBytes(Array As Byte(160,0,0,16))
    HandleMultipleBytes(Array As Byte(3,16,143,168,2,67,150,0,0,66,72,0,0,16,3,16,143,168,3,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,143,168,4,192,160,0,0,64,160,0,0,16,3,16,143,171,0,4))
    HandleMultipleBytes(Array As Byte(2,209,4,33,0,18,0,5,1,1,12,4,7,208,16,3,16))
    HandleMultipleBytes(Array As Byte(109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7,26,16,3))
    HandleMultipleBytes(Array As Byte(16,143,172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63))
    HandleMultipleBytes(Array As Byte(253,0,215,188,114,60,94,0,8,166,250,62,208,184,128,66,36,245,51))
    HandleMultipleBytes(Array As Byte(63,225,2,253,79,116,184,236,191,248,45,250,147,210,67,237,192,50))
    HandleMultipleBytes(Array As Byte(42,96,52,172,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,1,16,3,16))
    HandleMultipleBytes(Array As Byte(143,167,0,0,4,2,209,49,7,212,130,173,130,12,163,16,16,47,145,185,77,9,51,25,34,37,8))
    HandleMultipleBytes(Array As Byte(179,75,180,171,23,49,170,137,12,27,178,248,162,207,7,51,76,170,31,26,48,103,109,12,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,95,17,0,0,16,3,16,143,171,0,4,2,210,4,33,0,18,0,6,1,1,12,4,7,208,16))
    HandleMultipleBytes(Array As Byte(3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9))
    HandleMultipleBytes(Array As Byte(8,23,27,7,26,16,3,16,143,172,7))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,1,153,92,188,132,226,77,0,8,166))
    HandleMultipleBytes(Array As Byte(250,62,208,184,128,66,36,245,143,63,225,2,253,79,116,184,236))
    HandleMultipleBytes(Array As Byte(191,248,45,250,147,210,67,237,192,50,42,96,52,172,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,210,49,11,39,235,173))
    HandleMultipleBytes(Array As Byte(142,174,223,16,16,175,42,58,222,9,51,26,103,116,8,179,74,107,27,23,49,180,35,205,27,178,247,211,132))
    HandleMultipleBytes(Array As Byte(7,51,76,189,87,26,48,138,32,30,0,0,0,0,0,16,3))
    HandleMultipleBytes(Array As Byte(16,143,160,0,8,166,250,62,208,184,128,20,0,192,160,0,0,64,160,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,92))
    HandleMultipleBytes(Array As Byte(7,48,1,2,66,54,102,102,72,128,90,80,62,193,225,162,64,168,225,43,0,0,0,1,16,3,16,143,171))
    HandleMultipleBytes(Array As Byte(0,4,2,211,4,33,0,18,0,7,1,1,12,4,7,208,16,3,16,109))
    HandleMultipleBytes(Array As Byte(125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7))
    HandleMultipleBytes(Array As Byte(26,16,3,16,143,172,7,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,64,2,178,14,57,61,170,23,0,8,166))
    HandleMultipleBytes(Array As Byte(250,62,208,184,128,66,36,245,226,63,225,2,253,79,116,184,236,191))
    HandleMultipleBytes(Array As Byte(248,45,250,147,210,67,237,192,50,42,96,52,172,0,0,0,0,0,0,0,0,0,1,16,3,16))
    HandleMultipleBytes(Array As Byte(143,167,0,0,4,2,211,49,12,85,80,42,75,166,142,16,16,176,9,104,236,9,51,27,80,249))
    HandleMultipleBytes(Array As Byte(8,179,73,128,61,23,49,190,245,74,27,178,248,211,17,7,51,76))
    HandleMultipleBytes(Array As Byte(55,188,26,48))
    HandleMultipleBytes(Array As Byte(161,149,40,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,16,3,16,92,16,16,0))
    HandleMultipleBytes(Array As Byte(1,2,66,41,153,154,72,128,90,111,63,55,214,62,63,32,223,8,0,0,0,1,16,3,16,92))
    HandleMultipleBytes(Array As Byte(3,8,2,2,65,244,0,0,72,128,90,111))
    HandleMultipleBytes(Array As Byte(62))
    HandleMultipleBytes(Array As Byte(119,6,205,64,107,148,35,0,0,0,1,16,3,16,92,9))
    HandleMultipleBytes(Array As Byte(16,16,1,2,66,52,0,0,72,128,90,111,63,111))
    HandleMultipleBytes(Array As Byte(227,176,64))
    HandleMultipleBytes(Array As Byte(170,133,210,0,0,0,1,16,3,16,92,8,24,1,2,66,54,204,205,72,128,90,111,63,83,151,160))
    HandleMultipleBytes(Array As Byte(64,55,99,117,0,0,0,1,16,3,16,92,23,32,1,2,66,56,204,205,72,128,90,111,63,169,55,223))
    HandleMultipleBytes(Array As Byte(64,138,117,175,0,0,0,1,16,3,16,92,27,40,1,2,66,58,0,0,72,128,90))
    HandleMultipleBytes(Array As Byte(111,63,128,18,250,63,227,15))
    HandleMultipleBytes(Array As Byte(69,0,0,0,1,16,3,16,92,7,48,1,2,66,52,204,205,72,128,90,111,62,193,246))
    HandleMultipleBytes(Array As Byte(204,64,168,228,66,0,0,0,1,16,3,16,92,26,56,1,2,66,26,102,102,72,128,90))
    HandleMultipleBytes(Array As Byte(111,62,158,6,112,63,92,9,196,0,0,0,1,16,3,16,92,8,24))
    HandleMultipleBytes(Array As Byte(1,2,66))
    HandleMultipleBytes(Array As Byte(54,204,205,72,128,90,112,63,83,151,160))
    HandleMultipleBytes(Array As Byte(64,55,99,117,0,0,0,1,16,3,16,143,171,0,4,2,212,4,33,0,18,0,8,1,1,12,4,7))
    HandleMultipleBytes(Array As Byte(208,16,3,16,109))
    HandleMultipleBytes(Array As Byte(125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7,26,16,3))
    HandleMultipleBytes(Array As Byte(16,143,172,7,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,64,12,199,32,187,166,179,178,0,8,166,250,62,208,184,128))
    HandleMultipleBytes(Array As Byte(66,36,246,44,63,225,2,253,79))
    HandleMultipleBytes(Array As Byte(116,184,236,191,248,45,250,147,210,67,237,192,50,42,96))
    HandleMultipleBytes(Array As Byte(52,172,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,1,16,3,16,143,167,0,0,4,2,212,49,23,40,183,172,178,254,174,16,16,176,43,239,157,9,51))
    HandleMultipleBytes(Array As Byte(28,108,110,8,179,72,245,239,23,49,198,253,225,27,178,248,245,129,7,51,75,125,242,26,48,151,161,48))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,16,3,16,91,3,72,125,36,128,0,57,72,130))
    HandleMultipleBytes(Array As Byte(20,0,0,64,0,0,0,16,3,16,91,7,72,126,253,0,0,26,72,130))
    HandleMultipleBytes(Array As Byte(20,0,0,64,0,0,0,16,3,16,91,8,72,125,36,128,0,73,72,130))
    HandleMultipleBytes(Array As Byte(20,0,0,64,51,51,51,16,3,16,91,9,72,125,36,128,0,49,72,130,20,0,0,64,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,91,14,72,118,28,128,0,58,72,125,32,0,0,64,0,0,0,16,3,16,91))
    HandleMultipleBytes(Array As Byte(16,16,72))
    HandleMultipleBytes(Array As Byte(125,36,128,0))
    HandleMultipleBytes(Array As Byte(28,72,130,20,0,0,64,0,0,0,16,3,16,91,22,72,125,36,128))
    HandleMultipleBytes(Array As Byte(0,9,72))
    HandleMultipleBytes(Array As Byte(130,20,0,0,64,0,0,0,16,3,16,91,23,72,126,152,128,0,26))
    HandleMultipleBytes(Array As Byte(72,130,18,0,0,64,0,0,0,16,3,16,91,26,72,125,36,128,0,97,72,130,20,0))
    HandleMultipleBytes(Array As Byte(0,64,51))
    HandleMultipleBytes(Array As Byte(51,51,16,3,16,91,27,72,125,36,128,0,82,72,130,20,0,0,64,0,0,0,16,3,16))
    HandleMultipleBytes(Array As Byte(91,31,72,118,28,128,0,43,72))
    HandleMultipleBytes(Array As Byte(125,32))
    HandleMultipleBytes(Array As Byte(0))
    HandleMultipleBytes(Array As Byte(0,64,0,0,0,16,3,16,91,32,72,118))
    HandleMultipleBytes(Array As Byte(28,128,0,59,72,125,32,0,0,64,0,0,0,16,3,16,92,9,16,16))
    HandleMultipleBytes(Array As Byte(1,2,66,48,102,102,72,128,90,144,63,111,227,176,64,170,133,210,0,0,0,1,16,3))
    HandleMultipleBytes(Array As Byte(16))
    HandleMultipleBytes(Array As Byte(143,171,0,4,2,213,4,33,0,18,0,9,1,1,12,4,7,208,16,3))
    HandleMultipleBytes(Array As Byte(16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128))
    HandleMultipleBytes(Array As Byte(0,0,16,16,9,8,23,27,7,26,16,3,16,143))
    HandleMultipleBytes(Array As Byte(172,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,11,92,215,188,182,137,65,0,8,166,250,62))
    HandleMultipleBytes(Array As Byte(208,184,128,66,36,246,111,63,225,2,253,79,116,184,236))
    HandleMultipleBytes(Array As Byte(191,248,45,250,147,210,67,237,192,50,42,96))
    HandleMultipleBytes(Array As Byte(52,172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2))
    HandleMultipleBytes(Array As Byte(213,49,21,163,184,173,195,255,40,16,16))
    HandleMultipleBytes(Array As Byte(176,46,226,189,9,51,29,149,226,8,179))
    HandleMultipleBytes(Array As Byte(72,115,73,23,49,216,21,128,27,178))
    HandleMultipleBytes(Array As Byte(250,69,160,7,51,75,184))
    HandleMultipleBytes(Array As Byte(179,26,48,191,96,240,0,0,0,0,0,16,3,16,73,0,0,0,63,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,63,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,16,3,16,143,171,0,4,2,214,4,33,0,18,0,10,1,1,12,4))
    HandleMultipleBytes(Array As Byte(7,208,16,3,16,109,125,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27))
    HandleMultipleBytes(Array As Byte(7,26,16,3,16,143,172,7,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,64,15,17,137,188,248,209,226,0,8,166,250,62,208,184,128))
    HandleMultipleBytes(Array As Byte(66,36,246,171,63,225,2,253,79,116,184,236,191))
    HandleMultipleBytes(Array As Byte(248,45,250,147,210,67,237,192,50,42,96,52,172,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,1,16,3,16,143,167))
    HandleMultipleBytes(Array As Byte(0,0,4,2,214,49,25,158,95,174))
    HandleMultipleBytes(Array As Byte(5,149,138,16,16,176,40,224,188,9,51,30,35,41,8,179,71,253,208,23))
    HandleMultipleBytes(Array As Byte(49,216,144,208,27,178,251,105,102,7,51,75,7,161,26,48,156,168,58,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,85,19,3,1,8,16,3,16,143,171,0,4,2,215,4,33,0,18,0,11,1))
    HandleMultipleBytes(Array As Byte(1,12,4,7,208,16,3))
    HandleMultipleBytes(Array As Byte(16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7))
    HandleMultipleBytes(Array As Byte(26,16,3,16,143,172,7,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0))
    HandleMultipleBytes(Array As Byte(64,15,54,215,187,181,16,16,164,0,8))
    HandleMultipleBytes(Array As Byte(166,250,62))
    HandleMultipleBytes(Array As Byte(208,184,128,66,36,246,225,63,225,2,253,79,116,184,236,191,248,45,250,147,210,67,237,192))
    HandleMultipleBytes(Array As Byte(50,42))
    HandleMultipleBytes(Array As Byte(96,52))
    HandleMultipleBytes(Array As Byte(172,0,0,0,0,0,0,0,0,0,1,16,3,16,143,167,0,0,4,2,215,49,25))
    HandleMultipleBytes(Array As Byte(198,109))
    HandleMultipleBytes(Array As Byte(172,194,106,197,16,16,176,26,136,123,9,51,31,46,137,8,179,70,175,198,23,49,223,100,47,27))
    HandleMultipleBytes(Array As Byte(178,252,201,227,7,51,75))
    HandleMultipleBytes(Array As Byte(41,219,26,48,97,92,229,0,0,0,0,0,16,3,16,143,165,0,85,0,0,16,3,16,143,171,0,4,2))
    HandleMultipleBytes(Array As Byte(216,4,33,0,18,0,12,1,1,12,4,7,208))
    HandleMultipleBytes(Array As Byte(16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27))
    HandleMultipleBytes(Array As Byte(7,26,16,3,16,143,172))
    HandleMultipleBytes(Array As Byte(7,0,0,0,0,0,0,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,64,15,78,189,188,62,105,33,0,8,166,250))
    HandleMultipleBytes(Array As Byte(62,208,184,128,66,36,247,18,63,225,2,253,79,116,184,236,191,248,45,250,147,210,67,237,192,50,42,96,52,172))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0,0,0,0,0,1))
    HandleMultipleBytes(Array As Byte(16,3,16,143,167,0,0,4,2,216,49,25,224))
    HandleMultipleBytes(Array As Byte(22,173,76,115,175,16,16,176,19,247,198,9,51,31,123,210))
    HandleMultipleBytes(Array As Byte(8,179,69,137,130,23,49,230,82,44,27,178,254,101,234,7,51,75,14,250,26,48,52,227,41,0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(16,3,16,87,1,5,72,128,91,0,4,33,16,3,16,143,171,0,4,2,217,4,33))
    HandleMultipleBytes(Array As Byte(0,18,0,13,1,1,12,4,7))
    HandleMultipleBytes(Array As Byte(208,16,3,16,109,125,0,0,0,0,0,0,0,0,0,0,0,0,63,128,0,0,16,16,9,8,23,27,7))
    HandleMultipleBytes(Array As Byte(26,16,3,16,143,172))
    HandleMultipleBytes(Array As Byte(7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,12,43,91))
    HandleMultipleBytes(Array As Byte(188,233,105,151,0,8,166,250,62,208,184,128,66,36,247))
    HandleMultipleBytes(Array As Byte(62,63,225,2,253,79,116,184,236,191,248,45,250,147))
    HandleMultipleBytes(Array As Byte(210,67,237,192,50,42,96,52,172,0,0,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,0,0))
    HandleMultipleBytes(Array As Byte(1,16,3,16,143,167,0,0,4,2,217,49,22,129,118,173,250,159,238,16,16,176,83))
    HandleMultipleBytes(Array As Byte(225,94,9,51,32,32,150,8,179,68,107,86,23,49,231,62,34,27,179,0,2,13))
    HandleMultipleBytes(Array As Byte(7,51,74,216,201,26))
    HandleMultipleBytes(Array As Byte(48,53,23,3,0,0))
    HandleMultipleBytes(Array As Byte(0,0,0,16,3))
#END IF
   
End Sub
 
Upvote 0

emexes

Expert
Licensed User
Since DLE is not used as message ID, there should be no issue if the first data byte is ETX.
messages start with DLE (0x10) followed by anything other than ETX (0x03)
I feel like these two statements conflict.

Having said that, I also see that I've gotten this wrong:
B4X:
'1 = got initial DLE, waiting for non-DLE
so... bonus! one edit session = multiple fixes :-/
 
Upvote 0

emexes

Expert
Licensed User
so... bonus! one edit session = multiple fixes :-/
Job done :)

B4X:
Private PacketState As Int = 0
    '0 = idle, waiting for initial DLE
    '1 = got initial DLE, waiting for non-ETX
    '2 = in packet, waiting for data byte or DLE
    '3 = in packet, got DLE, waiting for DLE or ETX
B4X:
Sub HandleOneByte(B As Byte)
 
    Select Case PacketState
        Case 0:    '*** idle, waiting for initial DLE ***
            If B = DLE Then
                PacketState = 1
            Else
                'noise on line
                Log("wtf 58")
            End If
    
        Case 1:    '*** got initial DLE, waiting for non-ETX ***
            If B = ETX Then
                PacketState = 0    'ignore non-valid start sequence (aka empty packet?)
            Else If B = DLE Then
                PacketSize = 0
                PacketState = 3    'start receiving data, but with DLE prefix already active
            Else
                Packet(0) = B
                PacketSize = 1
                PacketState = 2    'start receiving data
            End If
        
        Case 2:    '*** in packet, waiting for data byte or DLE ***
            If B = DLE Then
                PacketState = 3
            Else
                If PacketSize < Packet.Length Then
                    Packet(PacketSize) = B
                End If
                PacketSize = PacketSize + 1
            End If
        
        Case 3:    '*** in packet, got DLE, waiting for DLE or ETX ***
            If B = ETX Then
                HandlePacket(PacketSize, Packet)
                PacketState = 0    'job done
            Else
                If PacketSize < Packet.Length Then
                    Packet(PacketSize) = B
                End If
                PacketSize = PacketSize + 1
            
                PacketState = 2    'resume processing normally
            End If
        
    End Select
 
End Sub
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
OK, you got me :) Messages start with the start of text delimiter DLE followed by the data payload. The data payload starts with a message ID which cannot include 0x03 by spec and which at the moment does not include the value 0x10 even though the spec does not say it could not. Since they also get to pick the message IDs they want to use, they happen to not use 0x10 as message ID.

I have the app running fairly well, except for the occasional (now rare) off-by-one on the Alcatel phone.
 

Attachments

  • Screenshot_20191126-214403.png
    Screenshot_20191126-214403.png
    68.8 KB · Views: 251
Upvote 0
Top