Giter VIP home page Giter VIP logo

Comments (6)

zsquareplusc avatar zsquareplusc commented on May 27, 2024

since 2.7 there is a flushInput/reset_input_buffer call at the end of open() maybe that makes a difference.

When a "dense" data stream is received (no pause between bytes) and the receiver is reset, it may lock onto a random 0 in the stream instead of a real START bit, which makes it receive "garbage". It will reacquire synchronization after 10 bits (depending on settings) idle line.

It may be that reset_input_buffer is passed down to the hardware (with some drivers) and also resets the receiver, not only the buffered bytes, triggering the conditions described above.

you could

  1. try if commending out reset_input_buffer to see if it makes a difference
  2. implement some synchronization that throws away partial packets / garbage until a correct set of data is received.

from pyserial.

MartinHjelmare avatar MartinHjelmare commented on May 27, 2024

Thanks for the suggestions!

I tried commenting out reset_input_buffer() in the open() method of class Serial (pyserial 3.0b1), in both serialposix.py and serialcli.py, but I didn't seem to have an effect, for the better, at least.

Regarding synchronization, I might look into that, but it feels like a lot of work on the application side, when it "just works" with an older version of pyserial.

serialposix.py

...
class Serial(SerialBase, PlatformSpecific):
    """\
    Serial port class POSIX implementation. Serial port configuration is
    done with termios and fcntl. Runs on Linux and many other Un*x like
    systems.
    """

    def open(self):
        """\
        Open port with current settings. This may throw a SerialException
        if the port cannot be opened."""
        if self._port is None:
            raise SerialException("Port must be configured before it can be used.")
        if self.is_open:
            raise SerialException("Port is already open.")
        self.fd = None
        # open
        try:
            self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
        except OSError as msg:
            self.fd = None
            raise SerialException(msg.errno, "could not open port %s: %s" % (self._port, msg))
        #~ fcntl.fcntl(self.fd, fcntl.F_SETFL, 0)  # set blocking

        try:
            self._reconfigure_port()
        except:
            try:
                os.close(self.fd)
            except:
                # ignore any exception when closing the port
                # also to keep original exception that happened when setting up
                pass
            self.fd = None
            raise
        else:
            self.is_open = True
        if not self._dsrdtr:
            self._update_dtr_state()
        if not self._rtscts:
            self._update_rts_state()
        #self.reset_input_buffer()
...

serialcli.py

...
class Serial(SerialBase):
    """Serial port implementation for .NET/Mono."""

    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
                9600, 19200, 38400, 57600, 115200)

    def open(self):
        """\
        Open port with current settings. This may throw a SerialException
        if the port cannot be opened.
        """
        if self._port is None:
            raise SerialException("Port must be configured before it can be used.")
        if self.is_open:
            raise SerialException("Port is already open.")
        try:
            self._port_handle = System.IO.Ports.SerialPort(self.portstr)
        except Exception as msg:
            self._port_handle = None
            raise SerialException("could not open port %s: %s" % (self.portstr, msg))

        self._reconfigurePort()
        self._port_handle.Open()
        self.is_open = True
        if not self._dsrdtr:
            self._update_dtr_state()
        if not self._rtscts:
            self._update_rts_state()
        #self.reset_input_buffer()
...

from pyserial.

zsquareplusc avatar zsquareplusc commented on May 27, 2024

as you say that 2.7 already shows the same problem, i've compared 2.5 and 2.7

serialposix.py has only minor differences, but notably:

  • at the end of open(), flushInput() is called in 2.7 (you already tested for that above)
  • _reconfigurePort only calls termios.tcsetattr when the settings have changed.
  • the set_special_baudrate function is implemented differently but should only be used with non-standard baudrates

could you run a test using 2.7 and replace the if at line 426 (or line 438 in pySerial 3.0b1) with if 1:, so that termios.tcsetattr is always called? maybe that has an effect on some drivers (if it is not called after open(), despite that the settings are already correct). if so, changing something after opening the port should also get rid of the issue (e.g. change the baudrate back and forth)

from pyserial.

patthoyts avatar patthoyts commented on May 27, 2024

I have been investigating the same problem using an Arduino device and reading the serial output using a Linux machine. I have eventually found that any change to the termios flags resolves the issue and it seems that we really must apply the tcsetattr flags to avoid this problem.

Some example code demonstrating the problem and its orignally posted to https://raspberrypi.stackexchange.com/q/37892/36775 but in fact it is not necessary to use SEVENBIT, using an alternate parity also worked. The patch posted now allows the correct flags and resolves the issue for me.

from pyserial.

zsquareplusc avatar zsquareplusc commented on May 27, 2024

Ah i see. The change to not always call tcsetattr was a patch that went into V2.6. Since SF changed the tracker item numbering scheme, it is also not easy to get hold on the original info about the patch. I guess it had something to do with glitches when _reconfigurePort is called. It is called often, after a change to the settings but it may or may not be needed on one or the other platform (e.g. changing the timeout, it is not needed on Posix but on Windows).

from pyserial.

MartinHjelmare avatar MartinHjelmare commented on May 27, 2024

Great to see a fix! Would it be possible to release a bugfix version of pyserial 2.7 at pypi? Otherwise I fear a lot of projects will still be using a possibly problematic version.

from pyserial.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.