2

I have been doing some port-reading for work, and I need to know if I should use asyncIO to read the data that comes in from this port.

Here's some details about the way in which the system is constructed.

  1. Multiple sensors are being read at the same time and might produce output that goes in at the same time. (all data comes in through a probee ZU10 connected to a usb port) All data must be timestamped as soon as it comes in.

  2. The data is supposed to be processed and then sent to a django webapp through a REST API.

The thing Is, it's really important not to lose any data, I'm asking about this because I believe there must be an easier way to do this than the one I'm thinking of.

The way I want the data to come in is through an asyncronous process that takes in the data into a queue and timestamps it, this way there is no way in which loss of data is present, and timestamping may be no more than a few fractions of a second off, which is not a problem.

If anyone has got any ideas I would be thankful for them

Here's the code I'm using to open the port, take the data in and what I've got so far on the actually reading the meaningful data.

Here's the reading part:

import serial #for port opening
import sys #for exceptions

#

#configure the serial connections (the parameters differs on the device you are connecting to)

class Serializer: 
    def __init__(self, port, baudrate=9600, timeout=.1): 
        self.port = serial.Serial(port = port, baudrate=baudrate, 
        timeout=timeout, writeTimeout=timeout)

    def open(self): 
        ''' Abre Puerto Serial'''
        self.port.open()

    def close(self): 
        ''' Cierra Puerto Serial'''
        self.port.close() 

    def send(self, msg):
        ''' envía mensaje a dispositivo serial'''
        self.port.write(msg)

    def recv(self):
        ''' lee salidas del dispositivo serial '''
        return self.port.readline()

PORT = '/dev/ttyUSB0' #Esto puede necesitar cambiarse


# test main class made for testing
def main():
    test_port = Serializer(port = PORT)

    while True:
        print(test_port.recv())

if __name__ == "__main__":
    main()

And a bit of what I'm going to be using to filter out the meaningful reads (bear with it, it might be full of awful errors and maybe a terrible RegEx):

import re
from Lector import ChecaPuertos
from Lector import entrada


patterns = [r'^{5}[0-9],2[0-9a-fA-F] $'] #pattern list

class IterPat:
    def __init__(self, lect, pat = patterns):
        self.pat = pat  # lista de patrones posibles para sensores
        self.lect = lect  # lectura siendo analizada
        self.patLen = len(pat)  #Largo de patrones

    def __iter__(self):
        self.iteracion = 0 #crea la variable a iterar.

    def __next__(self):
        '''
        Primero revisa si ya pasamos por todas las iteraciones posibles
        luego revisa si la iteración es la que pensabamos, de ser así regresa una
        tupla con el patrón correspondiente, y la lectura
        de otra forma para el valor de ser mostrado
        '''
        pattern = re.compile(self.pat[self.iteracion])
        comp = pattern.match(self.lect)
        if comp == True:
            re_value = (self.pattern, self.lect)
            return re_value
        else:
            self.iteración += 1

def main():
    puerto = ChecaPuertos.serial_ports()
    serial = entrada.Serializer(port = puerto[0])

    if serial != open:
        serial.open()
    while True:
        iter = IterPat()

     #This is incomplete right here.
paula.em.lafon
  • 553
  • 2
  • 6
  • 15
  • You certainly *can* use `asyncio` to read from a serial port, though I don't think you'll be able to use pyserial. See [here](https://groups.google.com/forum/#!topic/python-tulip/rPi4WPE_gVs). I don't think using `asyncio` is going to make your task easier or safer (in terms of not losing data), though. – dano Aug 03 '15 at 18:37
  • At 9600 baud, bytes will come at most 1 per ms, which shouldn't be too bad to poll (if perhaps inelegant). Serial ports often have buffers as well, and you could implement your own (arbitrarily sized) if you want with a blocking read in another thread/process. – Nick T Aug 03 '15 at 18:44
  • Are the serial port buffers implemented automatically or should I look them up? – paula.em.lafon Aug 03 '15 at 18:51
  • As Nick T said, you should set up a thread specifically for reading, and just use PySerial. Is the data streaming, and does latency matter? If the answers are yes and no, then the simplest thing to do is to read a fixed size chunk and immediately dump it in a queue. Otherwise the answer is probably to ask how many chars are available, and then read in max(avail, 1) (which will block if no data available) and then put variable-sized strings on the queue. – Patrick Maupin Aug 04 '15 at 01:13
  • Also, if you have any control whatsoever over the sending equipment, you can add simple error detection, or go nuts with forward error correction and/or retransmission. – Patrick Maupin Aug 04 '15 at 01:15
  • Yes, I absolutely want to add error detection, that's something I'll have to talk about with they guy who's programming the microcontrollers. Also, I'd like to know what the best way to go about setting up a reading thread would be. – paula.em.lafon Aug 04 '15 at 15:49

1 Answers1

2

I am using asyncio to read/write a serial port with pyserial. I am having my device on the other end of the serial connection write a single byte when it is ready to receive a payload. Asyncio watches for that byte then sends the payload. It looks something like this:

serial_f = serial.Serial(port=dev, baudrate=BAUDRATE, timeout=2)

def write_serial():
    status = serial_f.read(1)
    serial_f.write(buffer)

loop = asyncio.get_event_loop()
loop.add_reader(serial_f.fileno(), write_serial)
Joseph Sheedy
  • 6,296
  • 4
  • 30
  • 31