-
-
Save ashmigelski/21cdcb369f55444c4f26 to your computer and use it in GitHub Desktop.
| # -*- coding: utf-8 -*- | |
| import binascii | |
| import struct | |
| def parse(fmt, binary, offset=0): | |
| ''' | |
| Unpack the string | |
| fmt @see https://docs.python.org/2/library/struct.html#format-strings | |
| value value to be formated | |
| offset offset in bytes from begining | |
| ''' | |
| parsed = struct.unpack_from(fmt, binary, offset) | |
| return parsed[0] if len(parsed) == 1 else parsed | |
| def parsePacket(packet): | |
| ''' | |
| Parse Wialon Retranslator v1.0 packet w/o first 4 bytes (packet size) | |
| ''' | |
| # parsed message | |
| msg = { | |
| 'id': 0, | |
| 'time': 0, | |
| 'flags': 0, | |
| 'params': {}, | |
| 'blocks': [] | |
| } | |
| # parse packet info | |
| controller_id_size = packet.find('\x00') | |
| (msg['id'], msg['time'], msg['flags']) = parse('> %ds x i i' % (controller_id_size), packet) | |
| # get data block | |
| data_blocks = packet[controller_id_size + 1 + 4 + 4:] | |
| while len(data_blocks): | |
| # name offset in data block | |
| offset = 2 + 4 + 1 + 1 | |
| name_size = data_blocks.find('\x00', offset) - offset | |
| (block_type, block_length, visible, data_type, name) = parse('> h i b b %ds' % (name_size), data_blocks) | |
| # constuct block info | |
| block = { | |
| 'type': block_type, | |
| 'length': block_length, | |
| 'visibility': visible, | |
| 'data_type': data_type, | |
| 'name': name | |
| } | |
| # get block data | |
| block['data_block'] = data_blocks[offset + name_size + 1:block_length * 1 + 6] | |
| v = '' | |
| if data_type == 1: | |
| # text | |
| # TODO | |
| pass | |
| if data_type == 2: | |
| # binary | |
| if name == 'posinfo': | |
| v = {'lat': 0, 'lon': 0, 'h': 0, 's': 0, 'c': 0, 'sc': 0} | |
| (v['lon'], v['lat'], v['h']) = parse('d d d', block['data_block']) | |
| (v['s'], v['c'], v['sc']) = parse('> h h b', block['data_block'], 24) | |
| elif data_type == 3: | |
| # integer | |
| v = parse('> i', block['data_block']) | |
| elif data_type == 4: | |
| # float | |
| v = parse('d', block['data_block']) | |
| elif data_type == 5: | |
| # long | |
| v = parse('> q', block['data_block']) | |
| # add param to message | |
| msg['params'][name] = v | |
| # data blocks parse information | |
| msg['blocks'].append(block) | |
| # delete parsed info | |
| data_blocks = data_blocks[block_length + 6:] | |
| return msg | |
| if __name__ == '__main__': | |
| # test data | |
| data = [ | |
| '333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E666F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB0000001200047077725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001', | |
| '73686d6900552d3f49000000070bbb000000270102706f73696e666f001f090e42538d3b40af8c20a82dfc4a400000000000000000006c0109ff0bbb0000000f000461646331000000000000ca21400bbb00000011010361766c5f696e7075747300000000240bbb00000012010361766c5f6f7574707574730000000037' | |
| ] | |
| for i in range(len(data)): | |
| print '\nParse packet: %s\n' % data[i] | |
| print parsePacket(binascii.unhexlify(data[i])) |
| # -*- coding: utf-8 -*- | |
| import binascii | |
| import socket | |
| from parser import parse, parsePacket | |
| CONNECTION = (socket.gethostname(), 12374) | |
| server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| # prevent 'ERROR: Address already in use' | |
| server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
| server.bind((socket.gethostname(), 12374)) | |
| server.listen(1) | |
| print "Listen {0} on {1}".format(*CONNECTION) | |
| # Accept connections | |
| sck, addr = server.accept() | |
| print "Connected {0}:{1}".format(*addr) | |
| # packet queue | |
| queue = '' | |
| while 1: | |
| data = sck.recv(1024) | |
| if not data: | |
| break | |
| # append to queue | |
| queue = queue + data | |
| # get first packet size | |
| packet_size = parse('<i', queue) | |
| if packet_size + 4 <= len(queue): | |
| # get packet | |
| packet = queue[4:packet_size + 4] | |
| # print binascii.hexlify(packet) | |
| print parsePacket(packet) | |
| # remove packet from queue | |
| queue = queue[packet_size + 4:] | |
| # packet was received successfully | |
| sck.send(str(0x11)) |
Hi, I already started the server.py but I only have the message listen on 12374 port. But the screen have not shown anything else. Do I have to do something else or print something to look the packages. thanks.
The code works well. I had to open the port of centos. You could get the open ports in your linux with netstat -tulpn so you could look the ports. And you need to search in the firewall with the command. iptables -S. You need to have a rule to listen from that port.
Thanks for your code.
Hi Aleksey, thank you for this parsePacket function, I have found it very useful!
I noticed on some test data from a wialon local retranslator, that the latitude appeared to be in the 'lon' value and the longitude in the 'lat' value.
If I parse the following sample data using this function:
'333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E666F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB0000001200047077725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001'
it yields: 'posinfo': {'c': 326, 'h': 106.0, 'lon': 55.7305664, 'sc': 11, 's': 54, 'lat': 49.1903648} which locates to here: https://www.google.com/maps/search/+49.1903648+55.7305664
Is this correct? Or is it supposed to be here:
https://www.google.com/maps/search/+55.7305664+49.1903648
I modified lines 66-67 to the following, which appears to resolve for me:
v = {'lon': 0, 'lat': 0, 'h': 0, 's': 0, 'c': 0, 'sc': 0}
(v['lon'], v['lat'], v['h']) = parse('d d d', block['data_block'])
Could this be a mistake or could there be some other reason for this being jumbled up in my environment?
Hey @bshaw-au
WOW! What a bug) So many years it was in this code!
In spec 'posinfo' binary block has structure (lon-lat)
(bytes) Type Field description
8 Fractional value Lon - longitude
8 Fractional value Lat - latitude
So you're right, line 67 must be like this
-(v['lat'], v['lon'], v['h']) = parse('d d d', block['data_block'])
+(v['lon'], v['lat'], v['h']) = parse('d d d', block['data_block'])I already updated code
Thanks for reporting!
Example from doc http://extapi.wialon.com/hw/cfg/WialonRetranslator%201.0_en.pdf:
74000000333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E6
66F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB000000120004707
7725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001
But the null byte starts with 2 and parser not work
Profit :)
-controller_id_size = packet.find('\x00')
+controller_id_size = packet.find('\x00', 8)