0

I'm trying to use Python3 on Raspberry to communicate with a serial device. The protocol is as follows:

  1. Host sends command byte (contains address and data type)
  2. Device echos command byte
  3. Host sends operand byte (more data type info)
  4. Device echos operand byte as well as the first byte of data
  5. Host echos first byte of data. Device sends second byte of data. Repeat until 5 total data bytes

The device should only receive and send in binary (according to the outdated manual I've been referencing) but when I ask for the second data byte, I get "\t" or some other odd character. The command, operand, and first data byte all seem to work as they should. But after that I start getting some unexpected characters.

Is the device actually communicating in something other than binary?

My coding talents are still in the infant stages so ignore the overuse of print commands. Feel free to nitpick as I am new..

import serial
import time
import binascii

ser = serial.Serial(
    port='/dev/ttyUSB0',\
    baudrate=9600,\
    parity=serial.PARITY_NONE,\
    stopbits=serial.STOPBITS_ONE,\
    bytesize=serial.EIGHTBITS,\
    timeout = 2)

command=b"\x92"
operand =b"\x02"
sleepy = 0.2
data = bytearray()



while True:
    ser.write(command) #send command byte
    time.sleep(sleepy)
    print(ser.read(1)) #recieve command byte
    time.sleep(sleepy)


    ser.write(operand) #send operand byte
    time.sleep(sleepy)
    echo = ser.read(2)#recieve operand byte & first data byte
    print(echo)        
    time.sleep(sleepy)
    data.append(echo[1])

    ser.write(bytearray([echo[-1]])) #send first data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve second data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send second data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve third data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send third data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve fourth data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])

    ser.write(bytearray([echo[-1]]))    #send fourth data byte echo
    time.sleep(sleepy)
    echo = ser.read(10) #recieve 5th data byte
    print(echo)
    time.sleep(sleepy)
    data.append(echo[-1])
    print(echo[-1])
    print(data)




ser.close()

For example, when I run this I get the data array "(b'\x04\x08hT^')". I always get the first \x04 but the characters after that are random.

1 Answers1

0

I have since made this program work. I am still getting data with some unexpected characters but using binascii.hexlify followed by "{:08b}".format(int(c[1], base=16)) to convert it to the 8 bit binary that I need. Here's a look at what seems to work. For context, this program collects data from a moisture analyzer. So the math at the bottom is to convert the 40 bits of binary to a float value.

def get_h20():
data = bytearray()
echo = bytearray()
command=bytearray([146])
operand =bytearray([1])
sleepy = 0.02

ser = serial.Serial(
port='/dev/ttyUSB1',\
baudrate=9600,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout = 0)

data = bytearray()
ser.write(command) #send command byte
time.sleep(sleepy)
echo = ser.read(1) #recieve command byte
data = data + echo


ser.write(operand)
time.sleep(sleepy)
echo = ser.read(2)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo

ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo


ser.write(bytearray([echo[-1]]))
time.sleep(sleepy)
echo = ser.read(1)
data = data + echo
return(data)

ser.close()

converts raw h2o data to ppb

def raw_to_ppb (data):

raw_hex = str(binascii.hexlify(data[2:]))
c = [raw_hex[i:i+2] for i in range (0, len(raw_hex), 2)]
try:
    byte1 = "{:08b}".format(int(c[1], base=16))
    byte2 = "{:08b}".format(int(c[2], base=16))
    byte3 = "{:08b}".format(int(c[3], base=16))
    byte4 = "{:08b}".format(int(c[4], base=16))
    byte5 = "{:08b}".format(int(c[5], base=16))

    h20_bin = byte1+byte2+byte3+byte4+byte5

    m1 = h20_bin[14:16]
    m2 = h20_bin[17:24]
    m3 = h20_bin[25:32]
    m4 = h20_bin[33:40]
    m = m1+m2+m3+m4

    mantissa =      (int(m[0])*2**22+int(m[1])*2**21+int(m[2])*2**20+int(m[3])*\
                2**19+int(m[4])*2**18+int(m[5])*2**17+int(m[6])*2**16+int(m[7])*\
                2**15+int(m[8])*2**14+int(m[9])*2**13+int(m[10])*2**12+int(m[11])*\
                2**11+int(m[12])*2**10+int(m[13])*2**9+int(m[14])*2**8+int(m[15])*\
                 2**7+int(m[16])*2**6+int(m[17])*2**5+int(m[18])*2**4+int(m[19])*\
                 2**3+int(m[20])*2**2+int(m[21])*2**1+int(m[22])*2**0)/8388608

    e1 = h20_bin[5:8]
    e2 = h20_bin[9:14]
    e = e1+e2
    exponent = int(e,2)
    sign = (-1)**(int(h20_bin[4],2))

    h20_ppb = sign*(2**(exponent-127))*(1+mantissa)

    return(str(h20_ppb))
except:
    pass

I would still like to know more about the data format that is recieved from the analzyer. If I print the data variable from the the get_h2o function then I still get weird "b'\x04\x08hT^" responses... but python seems to know what to do with it.