Serial port does not work in rewritten Python code

2019-07-03 15:58发布

问题:

I have a Python program that reads some parameters from an Arduino and stores it in a database. The serial port is set up and used like this:

ser = serial.Serial(port=port, baudrate=9600)
ser.write('*')
while 1 :
    ser.write('*')
    out = ''
    # Let's wait one second before reading output (let's give device time to answer).
    time.sleep(1)
    while ser.inWaiting() > 0:
        out += ser.read(1)
    if out != '': 
        etc ... handling data

(The Arduino is set up so when it receives a star, it sends back a data string.) I would like to rewrite this as a daemon, so I am using the python-daemon library. In the init-part, I just define the port name, and then:

def run(self):
    self.ser = serial.Serial(port=self.port,baudrate=9600)
    while True:
        self.ser.write('*')
        out = ''
        # Let's wait one second before reading output (give device time to answer).
        time.sleep(1)
        while self.ser.inWaiting() > 0:
            out += self.ser.read(1)
        if out != '':
            etc ...

Everything is equal, except that I am now doing the serial handling within an App-object. The first version runs fine, when I try to run the latter, I get

File "storedaemon.py", line 89, in run
 while self.ser.inWaiting() > 0:
 File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 435, in inWaiting
 s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
 IOError: [Errno 9] Bad file descriptor

I am not able to see what has changed - except that I have tossed the code inside a new object. I have tried both to do the initialisation in init and in run, but I end up with the same result.

(The complete scripts are available at hhv3.sickel.net/b/storedata.py and hhv3.sickel.net/b/storedaemon.py.)

回答1:

During the daemonization of your app, all file handlers are closed except stdin, stderr and stdout. This includes the connection to /dev/log, which then fails with the fd error (so it looks like this has nothing to do with the serial fd, but instead with the handler's socket).

You need either to add this FD to the exclusion list:

class App():
    def __init__(self):
        ...
        self.files_preserve = [handler.socket]
        ...

Or alternatively, set up the handler after the daemon process forked:

class App():
    def run(self):
        handler = logging.handlers.SysLogHandler(address = '/dev/log')
        my_logger.addHandler(handler)
        my_logger.debug(appname+': Starting up storedata')
        ...

Both version ran fine during my tests.