LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

[Resolved] Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 8:56 am

Hello,

I am working on a RPI3, and I would like to send a hexadecimal frame to a counting device, with an RS232 serial link (USB / RS232 adapter), the frame once received, the count box immediately sends me back a result frame ( result of counting) (as soon as I execute, the frame is sent and the result is received), so I made a small code to send the result request frame, it is sent and the system of counting responds perfectly, because with a super terminal, I can see the frames sent and received.

My problem is that my code for reading the frame received at my raspberry, does not appear, the program runs but displays nothing!
here is the shipping code:

Code: Select all

 # -*- coding: utf-8 -*-
import serial                    
import struct                    
 
ser = serial.Serial(
    port='/dev/ttyUSB0',
    baudrate=9600,
    parity=serial.PARITY_ODD,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)
 
trame_envoi = [0x7E, 0x7E]
 
for i in trame_envoi:
    ser.write(chr(i))
To read the received frame I added this code on the same code above:

Code: Select all

x=ser.readline()
print (x)

This does not work (no display) knowing that the frame is well sent and well received, so I add another code by putting the reading lines on, like this:

Code: Select all

import time
import serial
 
ser = serial.Serial(
        port='/dev/ttyUSB0',
        baudrate = 9600,
        parity=serial.PARITY_ODD,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=1
)
 
while 1:
        x=ser.readline()
        print (x)
After that, always the same thing! after research I am told about buffer that must empty! (I did not quite understand), so I added in the reading code this line:

Code: Select all

ser.flush()
But still without success! When I say nothing is displayed, it is that the execution is done but does not stop, until I click Ctrl + c

  :?: Would anyone have any indications, or can propose a solution?

Thank you
Last edited by LinuxKoku on Wed Jun 27, 2018 12:47 pm, edited 1 time in total.
Thank you all :)

User avatar
topguy
Posts: 4550
Joined: Tue Oct 09, 2012 11:46 am
Location: Trondheim, Norway

Re: Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 10:57 am

"readline" probably expects an endofline character before it returns.
Read one and one character and print those instead.

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 12:10 pm

Thank you for your return,
How to do this? I have to create a loop?
Sorry but I do not know how to do that :| I can have a little example?
Thank you all :)

B.Goode
Posts: 6005
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 12:32 pm

Since you have chosen to import the serial library, it would be helpful to check the documentation to see what data handling facilities it provides. readline is only one of many possibilities..

http://pyserial.readthedocs.io/en/lates ... l_api.html

read might be what you need?

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 1:00 pm

To understand a little what I send and what I want to display, here is the code that I made:

Code: Select all

# -*- coding: utf-8 -*-

import serial                     
import struct                     

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

ser.flushOutput()
ser.flushInput()
ser.write(chr(0x7E) + chr(0x7E) +chr(0x73) + chr(0x02) + chr(0x73) + chr(0x02))
ser.flush()
print ser.read()

#After sending the frame above, I receive a result frame (confirmation) that I should display
#Result frame: 7E 7E 73 07 .....
I receive this error!

Traceback (most recent call last):
File "/home/pi/Desktop/serie.py", line 28, in <module>
print ser.read()
File "/home/pi/.local/lib/python2.7/site-packages/serial/serialposix.py", line 501, in read
'device reports readiness to read but returned no data '
SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)


With a super Terminal, I could visualize what I send the Raspberry Pi, and what the Raspberry PI receives, everything works! I just can not display what I get (the result frame)
Thank you all :)

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Mon Jun 25, 2018 3:32 pm

Try checking to see if data has been received before trying to get data

The pyserial module has the in_waiting property or inWaiting() function depending on which version of pyserial you are using.

For example

Code: Select all

while ser.inWaiting() > 0:
            print(ser.read(1))
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 9:53 am

Thank you for your answer,
Your code did not work but I understood how used the function inWaiting and I made this code the one that works very well, but that will cause me future worries, here is the code that works:

Code: Select all

# -*- coding: utf-8 -*-

import serial                     
import struct                     
import time
ser = serial.Serial(
    port='/dev/ttyUSB0',
    baudrate=9600,
    parity=serial.PARITY_ODD,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=0.1
)

ser.flushOutput()
ser.flushInput()
ser.flush()

ser.write((chr(0x7E) + chr(0x7E) +chr(0x73) + chr(0x02) + chr(0x73) + chr(0x02)).encode('ASCII'))

i=0

while i<11:
    time.sleep(0.1)
    if ser.inWaiting != 0:
        x=ord(ser.read(1))
        print(hex(x))
    i+=1
result:
0x7e
0x7e
0x73
0x7
0x0
0x0
0x0
0x0
0x0
0xa2
0x79
>>>     
If I put an infinite loop wihle 1, the loop will read the entire frame but after receiving this error below, it is for his that I used a counter to stop at the right moment, but the problem is that I have to always know the size of the frame!
on this code I put 11 because I know the frame that I have to receive

here is the error for an infinite loop:

Code: Select all

while  1:
    time.sleep(0.1)
    if ser.inWaiting != 0:
        x=ord(ser.read(1))
        print(hex(x))
        résult:
0x7e
0x7e
0x73
0x7
0x0
0x0
0x0
0x0
0x0
0xa2
0x79
Traceback (most recent call last):
  File "/home/pi/Desktop/serie.py", line 26, in <module>
    x=ord(ser.read(1))
TypeError: ord() expected a character, but string of length 0 found
>>>   
:?: I also tried to put the frame received in a table to use each bit, but I can not do it, indications?
Thank you all :)

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 10:10 am

If you are sending serial data you need to have someway to identify the start/end of a message and some way of knowing when you're finished.

For example
You could start your message with
0xDE 0xAD
Your python program looks for the two bytes appearing and then expects the next byte to contain the length of the message
0x05 (for example)
The program then knows that it should read a further 5 characters before stopping.

OR if you have a message with no fixed length.
Start the message with
0xDE 0xAD
and end it with
0xBE 0xEF.
Your python program will start reading on the first byte pair and stop reading on the second byte pair.

When you use serial.readline(), it expects all messages to end with a "/r/n" or "/n" character and it will only return a "complete line"

I wrote something many!! years ago to parse a message of a specific type. It is probably bad code given how much I've learnt since then but here it is as a rough idea. I used a loopback (connecting TX and RX pins together to test this).

Code: Select all

##
##  Message Format
##  Byte 0: Start Character - PROTOCOL_STX = 0xFE
##  Byte 1: Message Length = Message Type + Size of Message
##  Byte 2: Message Type
##  Byte 3-n: Message Data.
##
import serial
import struct
import time

PROTOCOL_STX = 0xFE
WAITING_FOR_STX = 0
WAITING_FOR_LENGTH = 1
WAITING_FOR_MSGTYPE = 2
WAITING_FOR_MESSAGE = 3

class SerialComms:
    def __init__(self,verbose=0):
        """
        Typical Usage:
        msg = SerialComms()
        msg = SerialComms(1) <- Shows Error/Status Messages
        """
        self._state = WAITING_FOR_STX
        self.msg_length = 0
        self.msg_type = 0
        self.message = []
        self._msg_count = 0
        self.verbose = verbose
    def _debug(self,message):
        """
        If the class is initialised with the verbose flag to
        1, then this class with print status messages.
        """
        if self.verbose:
            print message
    def get_msg(self):
        temp = ""
        for p in self.message:
            temp = temp + chr(p)
        return ''.join(temp)
    def process(self,c):
        """
        Populates a message from a datastream.
        @Reads: A single character from a datastream
        @Returns: True, if a complete message has been recieved.
                  False, if a complete message hasn't been recieved yet.
        Completed Message contained within self.message
        """
        if self._state == WAITING_FOR_STX:
            if ord(c) == PROTOCOL_STX:
                self._debug("Start Recieved")
                self._state=WAITING_FOR_LENGTH
                self._msg_count = 0
                self.message = []
        elif self._state == WAITING_FOR_LENGTH:
            self.msg_length = ord(c)
            self._debug("Length: "+str(self.msg_length))
            self._state = WAITING_FOR_MSGTYPE
        elif self._state == WAITING_FOR_MSGTYPE:
            self.msg_type = ord(c)
            self._debug("Msg Type: %s"%self.msg_type)
            self._state = WAITING_FOR_MESSAGE
        elif self._state == WAITING_FOR_MESSAGE:
            if self.msg_length - 1 == 0:
                return True
            if not (self._msg_count > self.msg_length - 1):
                self._debug("Part %s/%s" % (self._msg_count,self.msg_length-1))
                self.message.append(ord(c))
                self._msg_count += 1
                if self._msg_count == self.msg_length-1:
                    self._debug("Message Complete")
                    self._state = WAITING_FOR_STX
                    return True
        else:
            self._state=WAITING_FOR_STX

        return False

if __name__ == "__main__":
    #port = serial.Serial("COM1",9600,timeout=1)
    port = serial.Serial("/dev/ttyUSB0",9600,timeout=1)
    bus = SerialComms()
    port.write(struct.pack('BBBB', 0xFE,2,1,9))
    port.write(struct.pack('BBBBB',0xFE,3,2,3,1))
    port.write(struct.pack('BBBBB',0xFE,3,2,2,0))
    port.write(struct.pack('BBBBB',0xFE,3,2,5,0))
    port.write(struct.pack('BBB', 0xFE,2,3))
    port.write(struct.pack('BBBB', 0xFE,2,1,8))
    port.write(struct.pack('BBBB', 0xFE,2,1,3))
    port.write(struct.pack('BBBBIh',0xFE,9,0,123456,1234))
    time.sleep(0.2)
    
    while(port.inWaiting()>0):
        if (bus.process(port.read(1))):
            if bus.msg_type == 1:
                print "IR Send Request Recieved",
                print bus.message
            if bus.msg_type == 2:
                print "Switch Request Recieved",
##              print bus.message
                if bus.message[0] < 4 and bus.message[1] < 2:
                    print "Setting Switch %i to" % (bus.message[0]),
                    if bus.message[1] == 1:
                        print "On"
                    else:
                        print "Off"
                else:
                    print "Invalid Switch Set Request"
            if bus.msg_type == 3:
                print "Switch Status Request Recieved"
        
    port.close()
Last edited by scotty101 on Tue Jun 26, 2018 10:17 am, edited 2 times in total.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 10:13 am

You can also use exception handling so that your program ignores the TypeError and continues on regardless.

For example

Code: Select all

    if ser.inWaiting != 0:
        try:
            x=ord(ser.read(1))
            print(hex(x))
        except TypeError:
            print("No valid data received")
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 11:25 am

I executed your code, this one gives me the whole frame but after does not stop, until I click Ctrl + c!
Here's what I did with the result:

Code: Select all

while 1:
    
        time.sleep(0.1)
        if ser.inWaiting != 0:
            try:
                x=ord(ser.read(1))
                print(hex(x))
   
            except TypeError:
                print("No valid data ")
              

result:

0x7e
0x7e
0x73
0x7
0x0
0x0
0x0
0x0
0x0
0xa2
0x79
No valid data 
No valid data 
No valid data 
No valid data 
No valid data 
No valid data 
No valid data
 
Thank you all :)

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 11:29 am

:?: Now I would like to put these bytes (0x7e ...) in a table (list) to use them but I do not arrive after several tries, (For example I want to extract (0x7) which is the byte of the frame size that I would put in the loop while instead of 11, all these bytes have a meaning so I think to put them in a table)

for example: tab = my frame received --> [0x7e, 0x7e, 0x73, 0x7, 0x0, 0x0, ...]
knowing that in all the frames element 3 (0x7) is the byte of the size of the frame
so:
I would put:

Code: Select all

i = 0
tab = my frame received
while i <tab [3]
.
.
.
:?: first, I would like to make this list, indications?

I try her, but her gives nothing:

Code: Select all

i=0

while i<11:
    
        time.sleep(0.1)
        if ser.inWaiting != 0:
            x=ord(ser.read(1))
            z=print(hex(x))
            
           
        i+=1
tab=[z]
print(tab)

Result:

0x7e
0x7e
0x73
0x7
0x0
0x0
0x0
0x0
0x0
0xa2
0x79
[None]
>>> 
Last edited by LinuxKoku on Tue Jun 26, 2018 12:23 pm, edited 1 time in total.
Thank you all :)

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 12:09 pm

If you only want to read the data once you could break out of the while loop once no valid data is found

Code: Select all

if ser.inWaiting != 0:
        try:
            x=ord(ser.read(1))
            print(hex(x))
        except TypeError:
            print("No valid data received")
            break
Please note, the examples I give are just example, they are not intended to be something that you can just copy and paste in to your own code. Take the time to understand what it going on and make use of relevant parts of the example given. The worst way to learn to code is just blindly copying without understanding.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 12:11 pm

LinuxKoku wrote:
Tue Jun 26, 2018 11:29 am
:?: Now I would like to put these bits (0x7e ...) ....
knowing that in all the frames element 3 (0x7) is the bit of the size of the frame
You mean bytes. 0x7e is byte not a bit.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 12:19 pm

Yes, thanks :oops:
Thank you all :)

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 12:59 pm

The break makes it possible to leave the infinite loop, thank you very much
yes I agree with you but do not worry, I publish here, after making a lot of research and testing, thank you for your advice

as said above, I would extract each byte of the frame in a list for the used, after several tests and knowing that I read a lot on the lists, unfortunately, I still can not achieve it,

the table once created, here's how I want to use it for example:

Code: Select all

##----------------------------------##
print('------Test_1------')
##----------------------------------##

t=[1,2,3,4,5,6,7,'HiCrc','LoCrc']
x=t[3]
x2=t[-2]
x1=t[-1]

print('Size = ',x)
print('CRC_frame = ',x2,x1)

result:
------Test_1------
Size =  4
CRC_frame =  HiCrc LoCrc
So I know very well how to use each byte of the frame, my only problem is to put them in a table
Thank you all :)

scotty101
Posts: 2909
Joined: Fri Jun 08, 2012 6:03 pm

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 1:24 pm

If you are trying to add them to a list. you need to firstly create a blank list and then append each character to the end of the list.

For example (not copying and pasting)

Code: Select all

message = []
.....
c = ser.read(1)
......
message.append(ord(c))
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

LinuxKoku
Posts: 67
Joined: Wed May 16, 2018 9:16 am
Location: France

Re: Reading the serial port (RS232) of the Raspberry PI 3

Tue Jun 26, 2018 1:39 pm

I succeeded, thank you very much :mrgreen: you are great, and I learned a lot of things
Thank you all :)

Return to “Python”

Who is online

Users browsing this forum: No registered users and 13 guests