Serial port write

There are a lot of good serial port examples for reading from a serial port, but surprisingly little on writing to the port. While it looks straightforward, I do have one question. Is it possible to overflow the write buffer, and if so, how can this be prevented?

For my current project, I’m developing some external hardware that has a serial port. For testing, I’d like to have my XOJO app send this device a continuous stream of data. I could conceivably do something like this:

Do mySerialOutStream.write ("All work and no play makes Jack a dull boy.") Loop

Since the serial.write operation is asynchronous, this routine will keep adding more and more data to the buffer, which I’m sure is not a good idea. But there doesn’t appear to be any buffer full event or buffer full property. The only thing that appears to be suitable is to check the Serial.BytesLeftToSend property, and when it gets too big, then stop writing data to the buffer. But how big is too big? Or am I overlooking something simpler?

You could flush the buffer after every write.

I always flush the buffer when I know all the data I want to be sent has been written, that leaves no question about the transmission.

It’s not clear in the documentation whether the flush is synchronous or asynchronous. If it’s asynchronous then it won’t help, because I’m sending a never ending stream of data.

check the serial.bytesLeftToSend property and don’t write again until it’s zero. There’s no reason to backup data in the buffers, that just puts things behind realtime and it will continue after you stop. So let it get back to zero, or to within one packet length of zero before you write again. If there is no flow control involved then it will be sending out at the maximum speed for that baud rate, you could do some conservative math on the speed and calculate the time necessary to send as well. If there is flow control then bytesLeftToSend is the only option.

The serial.bytesLeftToSend property was actually the direction that I was leaning, but I was puzzled that there is no other way to do this. It seemed logical to me that there should be a write_buffer_empty event so that the main routine doesn’t have to keep checking.

Anyway, from the responses to my question, it appears that I haven’t overlooked any other options. So, thanks everyone for the suggestions.

I do a lot of work with serial ports as well, often talking to tiny devices with little or no buffers and I’ve been managing it with my own syncFlush methods forever just looping like:

while me.bytesLeftToSend > 0

but I’ve been doing it that way so long I couldn’t remember WHY I had to do it that way and decided to test the flush method. I think that either I don’t understand this as well as I thought, or something very strange is going on with the serial ports.

I did some testing and it seems that flush IS synchronous. And the other method of checking for bytes left to send no longer works. Sending 1024 bytes down a 300 baud serial port at 8N1 means sending 10240 bits so divide by 300 and you get about 34 seconds. Calling serial.flush I do indeed have the program thread hang up for just over 31 seconds, close enough.

If I use the other method of looping and checking the bytes left to send then I return in only a few milliseconds. So obviously the bytes left to send is coming from the programs serial buffer which is telling me how many bytes it has yet to offload to the buffer in the USB/Serial adaptor? Maybe? In any case the bytes left to send does not work anymore but flush does.

at least with larger packets it seems to work. With smaller packets it also returns too soon. When I send 512 bytes which should be 5120 bits at 300 baud my calculator says that should take 17 seconds to transfer, but flush returns in only 4 seconds.

I know that in the distant past bytesLeftToSend method did work, perhaps the USB Serial drivers no longer work the way they used to. With these chips at least it seems possible to flush and wait for larger packets, but not for smaller ones properly.

just for fun I decided to loop and send each byte separately with a flush for each one, and that returns in 300 milliseconds with 512 bytes, not the 17 seconds that it should take.

So it turns out this is more complicated than I thought, and when I bring some of those earlier projects up to the new OS versions and new compiler versions I’m going to have to revisit my thinking about flushing the port… Or my bitrate math is all wrong which is possible :wink:

I think I understand what is going on. From what you describe, it would appear that the XOJO serial object has it’s own buffer (possibly dynamically sized), and the USB/serial driver (part of the OS) also has its own buffer. Once the XOJO app sends data to the serial driver, it won’t have any further knowledge of the state of the OS driver buffer. So, bytesLeftToSend would only give the status of the XOJO serial buffer. That isn’t necessarily a bad thing, assuming that XOJO is still doing proper handshaking with the OS serial driver. It only means that at the very end of the transmission, you would still have to do a flush to make sure that the last of the data gets sent. But, the interim flow control could still use the bytesLeftToSend property.

I just received some FTDI USB/serial chips yesterday, and have started to experiment with them. I have a XOJO test app up and running, but need to interface the FTDI chips to a microcontroller, to process the data. That’s my project for today.

I use usb/ftdi serial alot, never had buffer overflow. I had to play with the flow control and the other settings to get things working right.

I use it for Arduino and Other brand RFID readers.

Derk, I’m trying to implement RTS/CTS flow control now, and it doesn’t seem to be doing anything. I’ll have to look deeper into the documentation, what little there is. I’ll probably have more questions later, but I’ll try some more experimenting first.

Xon, RTS, CTS all toys to play with. Some devices require certain settings. Probably in their documents somewhere.

I couldn’t get the CTS/RTS flow control signals to do anything under program control. After much head scratching, I looked a bit deeper into the FTDI documentation (on their site), and noticed that they mention problems with Apple’s FTDI CDC driver in versions of OSX prior to El Capitan (I’m still using Yosemite), and they recommended using their own driver. I installed their driver, and now the CTS/RTS flow control works the way it should. Talking to some others on a hardware related forum, someone mentioned a similar problem with the stock Windows driver on PC’s. They said that the problems went away when they replaced the Windows CDC driver with the FTDI driver.

ah, thats interesting and good to know. None of the devices I’m currently working with use any flow control at all so I haven’t noticed that but I’ll tuck it away in memory for the inevitable time when it bites me in the future.