I've written a simple Swift wrapper around libmodbus
, and it generally works fine. It serializes calls to the underlying C library on a Dispatch Queue (which then ends up being read/write operations on a serial bus).
Now I’m trying to add support for a libmodbus
call back function for setting a custom RTS bit. In my case, when this code is running on a Raspberry Pi, I need to manually set or reset a GPIO to properly enable the driver IC. libmodbus
provides support for this by allowing the client to specify a (C) callback function that tells it when to enable the driver.
In my wrapper, I’m trying to implement this with a delegate pattern, but there are two problems. One I can solve (the library doesn't provide for a way to pass a client context in the callback), so I don't technically have access to the delegate in the callback. This I can fix by enhancing libmodbus
.
The more serious problem is that I need to make a synchronous call in the callback to an Actor method (my delegate is an Actor), from this decidedly non-async context.
Here’s the code I initially wrote:
public protocol MODBUSContextDelegate : AnyObject
{
func tx(enable inEnable: Bool, for inCTX: MODBUSContext) async
}
public final class MODBUSContext
{
init(…)
{
…
if inCustomRTS
{
modbus_rtu_set_custom_rts(self.ctx)
{ inCtxPtr, inOn in
self.delegate?.tx(enable: inOn != 0, for: self)
// ^ 'async' call in a function that does not support concurrency
}
}
}
}
One solution might be to not use the delegate pattern here, but to just pass a closure to be called synchronously.
But is there a way to wrap this in Task {}
and then wait for that task to complete?