Best way to check checksum of bytes in python - python

I receive some packets from serial port. Packet example:
last 2 bytes
/\
[ data length ] [ data ] [packet crc]
I get crc, for example, b'w\x06'. Value is 125 (sum(b'w\x06') = 125). I calculate crc of packet: sum(data). And I get 1655. I know that 1655 is the same as b'w\06', but I do not know, how to translate it simply to 125 and compare with right checksum. What I need to convert 1655 to the same value as received packet bytes (125 or b'w\x06')? binascii/struct/something else?
Thanks

You can use int.from_bytes:
int.from_bytes(b'w\x06', 'little')
or with struct:
struct.unpack("<H", b'w\x06')[0]

Related

Why 1 incorrect data is sent when sending data over TCP?

Every time when ı running send to data matlab from python, my one data is going wrong. what is wrong ? or how can i send data to matlab from python. I think my problem is input buffer but ı cant find the right solution. Thanks for help.
This is wrong data
Python Code
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1',9999))
s.listen(1)
print('waiting for connection...')
sock, addr = s.accept()
count = 0
datas=[]
while True:
datas.append(random.random())
#datas.append(count)
s=str(datas[count])
sock.sendall(str(s).encode('utf-8'))
data = sock.recv(1024)
count = count + 1
print('Received', repr(data))
sock.close()
Matlab
t = tcpclient('127.0.0.1',9999);
all_signal_int = [];
all_signal_str= [];
count = 0;
while 1
write(t,"---");
while(1) % loop, until getting some data
nBytes = get(t,'BytesAvailable');
if nBytes > 0
break;
end
end
command_rev = read(t,nBytes); % read() will read binary as str
data = str2num(char(command_rev)); % transform str into numerical matrix
%data = char(command_rev); % transform str into numerical matrix
all_signal_int = [all_signal_int;data];
fprintf("%c \n",data);
count = count + 1;
%plot(all_signal_int,(all_signal_int+1000),'-r');
%drawnow;
end
TCP is not message based, rather it is a continuous stream of data. So if you do 100 sends of 4 bytes each, you cannot know if the client will receive:
400 bytes on the first read, or
1 byte on the first read followed by 399 bytes on the second read, or
136 bytes on the first read, 17 bytes in the second read and 247 reads of 1 byte each.
Also, there's no need to UTF-encode data because sockets can handle binary data.
Combining these two ideas leads to a fairly generally accepted solution which is to:
pack your floats into network-order IEEE754 4-byte floats before sending, and
always read 4 bytes off the socket at a time (usually by receiving in
a loop), and
then unpack at the other end.
See struct.pack() in Python and typecast in Matlab.

Read and write to port with unit8 format?

I have Matlab code that communicates over serial port, and I am trying to translate the code into python, however I am not getting the same "read" messages.
Here is the matlab code:
s = serial('COM3','BaudRate',115200,'InputBufferSize',1e6,'Timeout',2); %OPEN COM PORT
fopen(s);
string=[];
while(length(st)<1)
fwrite(s,30,'uint8'); %REQUEST CONNECTION STRING
pause(0.1);
st = fread(s,5); %READ CONNECTION (5BYTES, "Ready")
disp(st)
end
fwrite(s,18,'uint8'); % START ACQUISITION
while(1)
st(1:131) = fread(s,131); .....
disp(st)
OUT:
%first disp(st)
82
101
97
100
121
%from disp(st) second time
106
85
106
59
106
61
106
0
106...
Here is my attempt of python code:
# Open serial -
import serial
import time
s = serial.Serial('COM3', baudrate=115200, timeout=2 )
s.set_buffer_size(rx_size = 1000000, tx_size = 1000000)
#serieal is open
print ("serial is open: ", s.isOpen())
s.write(30) #request connection string
time.sleep(0.1)
string = s.read(5) #read connection string (5 BYTESm "Ready)
print (string)
# start aquisition
s.write(18) #request connection string
print (s.read(131))
however the output is, OUT:
serial is open: True
b'Uj.jg'
b'jVj3j-i\xefjOj8jajJj"i\xb8j\x19j4j,j\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\x9aj\x9aj\x8djfjkj/j\xa0j\x97jbjKj#i\xb9j\x1bj5j-j\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xaaUj\xe5j\xb7'
As you can see they aren't the same, so:
How do I send via pyserial a 'uint8' encoded number like in matlabs: fwrite(s,30,'uint8');
How do I read and display from pyserial similar to matlabs: st = fread(s,5);
How do I read and display from pyserial similar to matlabs: st = fread(s,5);
uint8 means 8-bit number. So 1 byte.
In python, you get a bytes object which is a sequence of bytes. You can iterate over it to get each value. - Which is exactly what you want, because that would be a value of one byte, 0-255
first = b'Uj.jg'
for i in first:
print(i)
This gives you:
85
106
46
106
103
How do I send via pyserial a 'uint8' encoded number like in matlabs: fwrite(s,30,'uint8');
You can convert your int to bytes object using int.to_bytes:
print((30).to_bytes(1, byteorder="big"))
Results in
b'\x1e'
First argument is number of bytes - in our case 1. Second argument is byte order - which is useless when we use 1 byte but it's still required.
So what you had as s.write(30) will be
s.write(b'\x1e')
or to keep the "30" thing visible just directly paste the conversion:
s.write((30).to_bytes(1, byteorder="big"))
Same for sending 18: s.write((18).to_bytes(1, byteorder="big"))

Recording binay data with pyserial and convert the data back to a readable output

I am trying to record binary sensor data with pyserial and convert it back to a readable output.
I recorded the data as a bytearray. This is a short example:
bytearray(b'~P\x1a\x004>e\x7f!>\xa2\xfa\x1dA\xff\x05]\xbd\xf5\xe6\x88\xbc!\x8eL\xbc1\xd5IV~Q\x1a\x004>bC\x1b>^j\x1dA00\xee<\xba\xf8\x88\xbb!\x8e\x00\x00\x00\x00O\xc7~R\x1a\x009>\x98k\x1a>Y\xf2\x1dA\x0f\x14*=\xa9\xb1\x88\xbb!\x8e\xaa<\xa9\xb1\xe38~S\x1a\x00;>\xa9\x0f\x19>HN\x1dA>\x02\x99=\xe4\x9f\xee\xbc\xba\xf8\x88;!\x8e\xa5~T\x1a\x00>>\xccW\x1c>j\x96\x1cA\xae\xfb\x88\xbc!\x8e\x88;!\x8e\x08\xbd!\x8e\xb1%~U\x1a\x006>x_\x19>HN\x1dA\xaf\x19\x88\xbc!\x8e\x08\xbd!\x8e\xaa\xbc\xa9\xb1<c~V\x1a\x004>e\x7f\x15>#\xca\x1dA00\x80=>\x05\xcc\xbc1\xd5\x88;!\x8eZ\x05~W\x1a\x00<>\xbb\xb3\x17>6\xaa\x1dAP.\x88\xbb!\x8e\xaa<\xa9\xb1*=\xa9\xb1(;~X\x1a\x00?>\xdd\xfb!>\x9e\x82\x1dA_\x0f\x88\xbc!\x8e\x08\xbd!\x8e\x08\xbc!\x8es\x1f~Y\x1a\x00A>\xf1\xdb\x1e>\x80\xb2\x1cA\xae\xfb\x88\xbb!\x8e\x08<!\x8e\x08\xbd!\x8e\xc0\xde~Z\x1a\x00;>\xa9\x0f\x14>\x11&\x1cAn\xff\x08<!\x8e\x88;!\x8e\x08\xbc!\x8e>:~[\x1a\x00;>\xa9\x0f\x10>\xed\xa1\x1dA\xa0)\x08<!\x8e\xee\xbc\xba\xf8;\xbdm\xc3\x1a\x10~\\\x1a\x00A>\xf1\xdb\x19>E\x12\x1dA0!L\xbc1\xd5\x08\xbc!\x8e\x08<!\x8e\xd3\x0f~]\x1a\x003>V\x17\x10>\xed\xa1\x1dA\xc16\x88;!\x8e\xcc<1\xd5\x88\xbc!\x8e\x07\x05~^\x1a\x00A>\xf1\xdb\x10>\xeae\x1cA\x1e\xf5\xee\xbc\xba\xf8\x08<!\x8e\x88;!\x8e\x8dh~_\x1a\x00<>\xbb\xb3\x12>\xfeE\x1dA\xff\x05\x88<!\x8e\x08\xbd!\x8e\x19=\xe4\x9f\xcfd~\x1a\x004>g\xbb\x10>\xed\xa1\x1dA "\x08\xbc!\x8e\x08\xbc!\x8e\xaa\xbc\xa9\xb1M\xc8~a\x1a\x009>\x98k\x12>\xfb\t\x1dA0!\x00\x00\x00\x00\x08<!\x8e\x88\xbb!\x8e\x12\xb4~b\x1a\x008>\x8a\x03\x1c>j\x96\x1dA\xef\x15]\xbd\xf5\xe6\x19=\xe4\x9f\x08\xbd!\x8e\xa3Z~c\x1a\x007>\x85\x8b\x12>\x00\x82\x1dA>\x02\x08<!\x8e\xcc<1\xd5\x08\xbc!\x8e\x84\x11~d\x1a\x00<>\xbb\xb3\x13>\x0f\xea\x1cAn\xff\x08<!\x8e\xcc\xbc1\xd5*=\xa9\xb1#6~e\x1a\x00<>\xbd\xef\x14>\x11&\x1dA\xef\x15\x88\xbb!\x8e\x88\xbc!\x8e\x88\xbb!\x8e\xcc\xa9~f\x1a\x00>>\xccW\x1c>j\x96\x1dA\x0f\x14\x80\xbd>\x05\x88<!\x8e\xcc<1\xd5Y\xe1~g\x1a\x00E>\x13$!>\xa0\xbe\x1dA\xb0(\xaa\xbc\xa9\xb1*=\xa9\xb1\xee<\xba\xf8R\xa1~h\x1a\x00#>\xe07\x19>HN\x1dA\xe04\xee<\xba\xf8\xee<\xba\xf8\x88;!\x8eI3~i\x1a\x00<>\xbd\xef\x19>HN\x1dAO\x10*=\xa9\xb1L<1\xd5\xee<\xba\xf8$f~j\x1a\x00#>\xe07%>\xc5B\x1cA\xae\xfb\x88;!\x8e\x08\xbc!\x8eL\xbc1\xd5\xa4\x12~k\x1a\x004>bC)>\xec\x02\x1cAn\xff\x88\xbc!\x8e*=\xa9\xb1\x08\xbc!\x8e\xe0\xb1~l\x1a\x00->\x1d\xb3,>\x0fK\x1dA\xcf\x08\x00\x00\x00\x00\x08<!\x8e\xee<\xba\xf8\x8b\x15~m\x1a\x00,>\x0c\x0f">\xa7r\x1dA\xef\x06L<1\xd5\xcc\xbc1\xd5\x08<!\x8e\x1eA~n\x1a\x005>q\xab >\x91V\x1cAm\xe1\xcc<1\xd5\x08=!\x8e\xcc\xbc1\xd5\xb4\x8d~o\x1a\x00,>\x0c\x0f.>"+\x1dA\x8f\x1b]\xbd\xf5\xe6\xaa\xbc\xa9\xb1;\xbdm\xc3\xcaN~p\x1a\x004>bC">\xa56\x1dAN\x01\x08<!\x8e\x88\xbc!\x8e\x19=\xe4\x9f\n')bytearray
Now I need to convert the data back to a readable out. The structure should look like:
Byte: SYNC = 0x7E
Byte = sample counter 0...255
Byte = Package length
Followed by:
3 * float_32 (IACC) -> Sensor1
3 * float_32 (IOMG) -> Sensor2
2 Byte CRC16
Thank your for the help.

Serial Port data

I am attempting to read the data from an Absolute Encoder with a USB interface using pyserial on the Raspberry. The datasheet for the encoder is below. The USB interface data is on page 22-23
https://www.rls.si/eng/fileuploader/download/download/?d=0&file=custom%2Fupload%2FData-sheet-AksIM-offaxis-rotary-absolute-encoder.pdf
I have successfully connected to the Encoder and I am able to send commands using
port = serial.Serial("/dev/serial/by-id/usb-RLS_Merilna_tehnkis_AksIM_encoder_3454353-if00")
port.write(b"x")
where x is any of the available Commands listed for the USB interface.
For example port.write(b"1") is meant to initiate a single position request. I am able to print the output from encoder with
x = port.read()
print(x)
The problem is converting the output into actual positiong data. port.write(b"1") outputs the following data:
b'\xea\xd0\x05\x00\x00\x00\xef'
I know that the first and last bytes are just the header and footer. Bytes 5 and 6 are the encoder status. Bytes 2-4 is the actual position data. The customer support has informed me that I need to take bytes 2 to 4, shift them into a 32 bit unsigned integer (into lower 3 bytes), convert to a floating point number, divide by 0xFF FF FF, multiply by 360. Result are degrees.
I'm not exactly sure how to do this. Can someone please let me know the python prgramming/functions I need to write in order to do this. Thank you.
You have to use builtin from_bytes() method:
x = b'\xea\xd0\x05\x00\x00\x00\xef'
number = 360 * float(
int.from_bytes(x[1:4], 'big') # get integer from bytes
) / 0xffffff
print(number)
will print:
292.5274832563092
This is the way to extract the bytes and shift them into an integer and scale as a float:
x = b'\xea\xd0\x05\x00\x00\x00\xef'
print(x)
int_value = 0 # initialise shift register
for index in range(1,4):
int_value *= 256 # shift up by 8 bits
int_value += x[index] # or in the next byte
print(int_value)
# scale the integer against the max value
float_value = 360 * float(int_value) / 0xffffff
print(float_value)
Output:
b'\xea\xd0\x05\x00\x00\x00\xef'
13632768
292.5274832563092

Python: Convert packet object/inet object to 32 bit integer

I have IPv4 address and want to convert it to 32 bit integer.
i am able to convert IPv4 address into string using socket.inet_ntop and then convert that string to 32 bit integer
but is there a direct way?
An IPv4 address in its basic form is a 32-bit integer in network byte order.
I'm assuming you have it as a sequence of bytes (because that is what you would normally hand off to inet_ntop).
What you will need to convert it into a python integer is the struct module and its unpack method along with the "!I" format specification (which means network byte order, unsigned 32-bit integer). See this code:
from socket import inet_ntop, inet_pton, AF_INET
from struct import unpack
ip = inet_pton(AF_INET, "192.168.1.42")
ip_as_integer = unpack("!I", ip)[0]
print("As string[{}] => As bytes[{}] => As integer[{}]".format(
inet_ntop(AF_INET, ip), ip, ip_as_integer))
You could of course also reconstruct the integer bytewise:
ip_as_integer = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | ip[3]

Categories

Resources