0

I use the following piece of code to read the serial port until i get a terminating character.

"""Read until you see a terminating character with a timeout"""
    response=[]
    byte_read=''
    break_yes=0
    time_now = time.clock()
    while ((not (byte_read=='\r') ) and (break_yes==0)):
        byte_read = self.ser.read(1)
        if (not(len(byte_read)== 0) and (not (byte_read =='\r'))):
            response.append(byte_read)
        if ( time.clock() - time_now > 1 ):
            if self.DEBUG_FLAG: 
                print "[animatics Motor class] time out occured. check code"
            break_yes=1
    if break_yes==0:
        return ''.join(response)
    else:
        return 'FAIL'

This works well but because of the while loop, the cpu resources are taken up.

I think that having a blocking read(1) with a timeout will save some of the cpu. The flag i am looking for C is "MIN == 0, TIME > 0 (read with timeout)" in termios

i am looking for a similar flag in Python.

I could also use the io.readline to read till i get '\r', but i want to stick to pyserial as much as possible without any other dependency.

Would greatly appreciate advice. Do let me know if i should do it in a completely different way either too.

Thanks,

  • According to the documentation, read() should be a blocking operation. You don't show how you open the serial port, please supply that part, too. beyond that, your code is quite unpythonic. Python has bools, don't use integers as flags. It also has a !=-operator, no need to use a confusing "not a == b". Python has a break-statement to leave loops, no need to emulate that with a flag. Using that would remove more or less 80% of your code, while keeping the same semantics. Returning strings with "FAIL" as error-message when the expected result is also a string calls for trouble. Return None. – deets Jun 18 '15 at 22:47
  • @deets I open the port with `serial.Serial("port_string","baud_rate", timeout=0)` The timeout =0 for making it non blocking. What I want is it to block until it has 1 byte and return immediately with that byte, and not wait for the entire duration given for the timeout. I will be editing the code as per your comments, since it makes better sense, once i figure out this issue. – vamshi konduri Jun 20 '15 at 01:13

2 Answers2

1

You should read the documentation of Pyserial: it clearly states that a timeout of 0 as you pass it to the constructor will turn on non-blocking behaviour:

http://pyserial.sourceforge.net/pyserial_api.html#classes

Just get rid of the timeout parameter, and you should be set.

deets
  • 6,285
  • 29
  • 28
  • 1
    Dude, i read the documentation. You did not read my comment. I'll check if i find a solution and update it here. Thanks for the help. – vamshi konduri Jun 22 '15 at 18:25
  • Ah. I misunderstand your question and didn't realize the timeout requirement. Still, according to the documentation you could pass that very timeout to your serial open call. IMHO simpler than the select call, but that obviously works. – deets Jun 23 '15 at 14:29
  • The problem i faced with the timeout is that it blocks till the entire timeout period is done, and does not return immediately when there is data. So i had to resort to select, which saves system resources till there is data. I also edited the code to make it more "pythonic", except for the return value. cant do that without chaging a bunch of other code. – vamshi konduri Jun 24 '15 at 16:47
0

Aight, so I found out a way. Instead of polling with the no timeout, I use the select module in python, which is similar to the one in C.

It returns if any data is available immediately, or waits for the timeout period and exits, which is precisely what i wanted. I took deets comments for cleaning up the code and it looks like so now.

def readOnly(self):
"""Read until you see a terminating character with a timeout"""
    response=[]
    byte_read=''
    while (not (byte_read=='\r')):
        reading,_,_ = select.select([self.ser], [], [], 1) #returns immediately if there is data on serial port. waits 1 second to timeout if not.
        if reading !=[]:                                   #something is to be read on the file descriptor
            byte_read = self.ser.read(1)
            if (byte_read !='\r'):
                response.append(byte_read)
            else:                                          #'\r' received
                return ''.join(response)
                break
        else:
            if self.DEBUG_FLAG: 
                print "[Motor class] time out occured. check code"
            return 'FAIL'
            break

`

This decreased the cpu usage from 50% to 5% so life is better now.

Thanks,