Asynchronous Swift serial port wrapper best approach?

I’m finding I may need to implement my own MODBUS communications library in Swift, but even if I do, I still run into the need to support cross-platform (macOS & Linux) serial port access, and the only way I can see to do that is to call the POSIX APIs for this, which end up being blocking C calls.

What I did before was create a DispatchQueue that I do async dispatches on within withCheckedThrowingContinuation blocks. This forces all reads & writes on the serial port to be serialized.

Is this the right approach (using the DispatchQueue)? It also seems that the serial port wrapper class should be an Actor, would you agree?

Assuming that much is correct, then the higher-level abstraction of implementing the MODBUS protocol involves writing a packet of bytes on the serial port, and then reading a response packet, verifying the checksum, and deserializing the data and handing it back to the caller. This MODBUS object should probably also be an Actor, and also a work queue to serialize these pairs of operations (write followed by read). The client of the MODBUS library, in this case, is a webserver that may make a number of MODBUS requests that aren't otherwise serialized. Does this seem correct?

I'm second-guessing myself in this design and I'm hoping I'm not missing some obvious other way to do this. TIA!

I think your original approach is totally fine. If you need concurrent reading and writing then you could use two queues instead of one.

1 Like

I generally use Dispatch I/O for this sort of thing. For the details, see the dispatch_io_create man page.

One trick there is to dup the descriptor so you can have separate input channel and output channels.

To be clear, I’m doing this on Apple platforms. AFAIK these APIs are present on other platforms but I’ve no direct experience with them.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like