Serial monitor, monitor_eol, and send_on_enter

I am updating my Mechatronics course labs to use VSCode+PlatformIO instead of ArduinoIDE. For the most part, it has been going great and I really think the students are going to like it. However, I ran into one minor problem.

In one of our labs, we have students learn how to use the map() function and also create a custom y=mx+b function to convert between desired servo position and the associated microseconds from the servo motor datasheet. In the past, we have always has them use the parseInt or parseFloat function to read from the serial port. Of course, in the ArduinoIDE we always had to have them set the EOL to “None”. This was necessary because parseInt is a little deficient in that it sees the original int correctly, but then parses the EOL also and returns zero.

However, the PlatformIO console doesn’t have an option for EOL=None. We had been trying with
monitor_filters = send_on_enter
monitor_eol = LR
but it fails for the same reason it would fail in ArduinoIDE if we didn’t set the serial monitor EOL to None.

So, we found two workarounds, namely using Serial.readString() and then toInt(). My question is whether the PlatformIO team would be open to adding another option for monitor_eol, namely NONE. I think the code change would be as simple as adding the following 2 lines of code to the SendOnEnter class in the send_on_enter.py file.

        if self.options.get("eol") == "CR":
            self._eol = "\r"
        elif self.options.get("eol") == "LF":
            self._eol = "\n"
+       elif self.options.get("eol") == "NONE":
+           self._eol = ""
        else:
            self._eol = "\r\n"

This would allow for a similar option set for the EOL as the ArduinoIDE and would make the parseInt not be broken for use with the PlatformIO monitor.

I don’t think so because of the TX function below checking if the text ends with the given EOL as the “go” condition, and with that change it would check against endswith empty string, which would always trigger…

So I think this can be specially handled by just waiting for an enter press and then remove the \n or \r end characters from the buffer.

If you figure out a working version you can PR it into Pull requests · platformio/platformio-core · GitHub. Alternative open an issue in Issues · platformio/platformio-core · GitHub to get a discussion with the developers going.

1 Like

I see. I clearly didn’t check the tx function as carefully as a I should have. I think I have an alternative. The END_OF_MEDIUM non-printable character isn’t regularly used anymore, so I am thinking of using that as the end of buffer marker for the monitor_eol=NONE option

class SendOnEnter(DeviceMonitorFilterBase):
    NAME = "send_on_enter"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._buffer = ""

        if self.options.get("eol") == "CR":
            self._eol = "\r"
        elif self.options.get("eol") == "LF":
            self._eol = "\n"
+        elif self.options.get("eol") == "NONE":
+            self._eol = "\x19"
        else:
            self._eol = "\r\n"

    def tx(self, text):
        self._buffer += text
        if self._buffer.endswith(self._eol):            
            text = self._buffer
            self._buffer = ""

+            # If the EOL is set to None, remove the placeholder character.   
+            if self._buffer.endswith("\x19"):
+                self._buffer = self._buffer[:-1]
            return text
        return ""

I will get this tested and submit a PR. Do you think it matters which non-printable ASCII character I should use? There are a lot of them and this one seemed to almost fit the bill even in description. I could probably use ETC, FS, GS, RS, or US also. Maybe the End of Transmission Block (ETB) would be a more logical choice, but really any of these should work. See https://www.lammertbies.nl/comm/info/ascii-characters for interesting description/history about some of the lesser used ASCII codes.

I think the only time this could bite someone is if they were intentionally copying a bunch of non-printable characters and then pasting them into the serial monitor. The code above would eat the 0x19 characters and not send them.

But self._buffer is already empty string at that point, you would have to test and modify the text variable.

Take you time playing around with this and testing it, or just open an issue and leave it in the hands of the developers.

Strictly said though I think Arduino code should be able to handle whatever setting you put on the serial monitor (also in the Arduino IDE), so using readString() and then toInt() isn’t a bad thing, it’s more correct in fact and resistant to different line endings.

I had those lines of code above the
text = self._buffer
but then moved it below because I thought that we should make the modification of the outgoing buffer as atomic as possible (I wasn’t sure if there was some way that the buffer could get modified in the interim if someone was still typing quickly). I had intended to change it to “text” after I moved it below and then spaced it before actually posting.

I agree that fixing things like parseInt would be good so that it could better handle entire lines of code including LF and/or CR. I has messed around with the LookAheadMode that they had, but it didn’t seem to fix this issue. However, that seems like a much bigger effort from the standpoint of making sure it doesn’t break anything on the millions of boards out there. This at least isolates this capability to the very few people who actively put it in this mode of operation.

As a side note, when making the PR, I would also like to make sure the documentation gets updated to show that this is now an option. It doesn’t seem as if the documentation for send_on_enter gets automatically generated from comments in that source file. I would like the PR to be complete. Can you point me to where the documentation is at?

Yes, you would have to PR into GitHub - platformio/platformio-docs: PlatformIO Documentation, specifically this file.