RAW CAN decoding

2019-08-26 19:17发布

问题:

I'm trying to import CAN data using a virtual CAN network and am getting strange results when I unpack my CAN packet of data. I'm using Python 3.3.7

Code: import socket, sys, struct

sock = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
interface = "vcan0"
try:
    sock.bind((interface,))
except OSError:
    sys.stderr.write("Could not bind to interface '%s'\n" % interface)


fmt = "<IB3x8s"

while True:
   can_pkt = sock.recv(16)
   can_id, length, data = struct.unpack(fmt, can_pkt)
   can_id &= socket.CAN_EFF_MASK
   data = data[:length]
   print(data, can_id , can_pkt)

So when I have a CAN packet looking like this.

candump vcan0: vcan0  0FF   [8]  77 9C 3C 21 A2 9A B9 66
output in Python: b'\xff\x00\x00\x00\x08\x00\x00\x00w\x9c<!\xa2\x9a\xb9f'

Where vcan0 is the interface, [x] is the number of bytes in the payload, the rest is an 8 byte hex payload.

Do I have the wrong formatting? Has PF_CAN been updated for newer Python version? Am I using CAN_RAW when I should be using CAN_BCM for my protocol family? Or am I just missing how to decode the unpacked data?

Any direction or answer would be much appreciated.

Also, here are some script outputs to can-utils values I've plucked. If I can't find anything, I'm probably just going to make collect a ton of data then decode for the bytes of data that don't translate over properly. I feel that i'm over complicating things, and possibly missing one key aspect.

Python3 output == can-utils/socketCAN (hex) 
M= == 4D 3D 
~3 == 7E 33
p == 70 
. == 2E 
@ == 40
r: == 0D 3A 
c == 63
5g == 35 67 
y == 79
a == 61 
) == 29
E == 45
M == 4D
C == 43
P> == 50 3E
SGN == 53 47 4E
8 == 38

回答1:

Rather than laboriously complete that table you started, just look at any ASCII code chart. When you simply print a string, any characters that are actually ASCII text will print as that character: only unprintable characters get shown as hexadecimal escapes. If you want everything in hex, you need to explicitly request that:

import binascii

print(binascii.hexlify(data))

for example.



回答2:

I'm sure you've already run into the python-can library? If not we have a native python version of socketcan that correctly parse data out of CAN messages. Some of the source might help you out - or you might want to use it directly. CAN_RAW is probably what you want, if you plan on leaving virtual can for real hardware you might also want to get the timestamp from the hardware.

Not all constants have been exposed in Python's socket module so there is also a ctypes version which made in easier to experiment with things like the socketcan broadcast manager. Docs for both are here.