I’m finally getting around to trying DispatchIO, but I have questions. My current need is this: I want to open a serial port and get called back whenever data arrives. I want to send data arbitrarily.
I'm trying various combinations of opening with O_NONBLOCK, opening the tty or cu, and VMIN and VTIME. Looking at the termios man page and experimenting, it seems what I want is:
- Noncanonical mode
- Non-blocking
VMIN = 0, VTIME = some timeout (I've been trying 25 * 10)
Unfortunately, my reads aren’t blocking as I would expect (I would expect them to block until the requested data is received, or 25 seconds have elapsed). The read closure is called immediately (with no data, unless some was sent before the call).
If I don’t pass O_NONBLOCK to open(), and try to open the tty, it blocks forever, I think waiting for some additional serial lines to be set.
If I try VMIN=1, then it will (theoretically) block forever until the first byte is received. I need this read to time out.
My intent is to create a queue to hold a task that loops over blocking read calls. If the calls don’t block, that will result in a very tight loop, wasting resources.
Questions
- How do I get my reads to block with a timeout? Even if I open without
O_NONBLOCK (on a cu port), or use fcntl() to clear O_NONBLOCK, read never blocks for VMIN==0 and VTIME==50. If VMIN==1, the call never returns, even after a byte is received (because my reads are for 1024 bytes. It does return if I send 1024 bytes).
- What is the purpose of the queue passed to
DispatchIO()? What work is being done on that queue?
- Does the queue passed to
DispatchIO() have to be different from the queue I create to read?
- A problem I ran into with regular Posix
read() calls is that if I try to close the port while a read is pending, the whole thing just seems to hang (quite hard, I can't break in the debugger, although I can kill the app). How do I stop a pending read?
Note that by "returns,” I mean the receive callback isn’t called.
Why might I want separate input and output channels? Can I also use DispatchIO(type:io:queue:cleanupHandler:)
My code is available here. The relevant files are Serial.swift and GroundStationApp.swift:29, 55, 61. I have two FTDI USB-serial adapters connected to each other. On one I run screen in the terminal, and this app connects to the other (the path is hard-coded here: GroundStationApp.swift:33). Note that the link to the repo is to the specific commit as it stands right now.