Threaded Application Support - I2C, SPI, GPIO
MotivDev opened this issue · comments
Board Type
BalenaFin 1.0
Operating System
Raspbian
Swift Version
v4.2 / v5 - prebuilt
Description
I apologize in advance for posting this question here.... I looked on SO and there does not seem to be a SwiftyGPIO group there... maybe I missed it? If there is another location I should be getting guidance please tell me and I will post there and close this issue.
I have an embedded application using DispatchQueues and wondering what the best way to control access to the I2C, SPI and GPIO from multiple threads would be for this library. I was thinking about wrapping each bus in its own DispatchQueue, but this sounds like way too many changes to the library to support this. I've looked at LinkerKit for examples, but not too keen on their methodology. Thought of dropping back to a round robin style polling, but this just sounds bad and we loose some of the scheduling capabilities.
Any guidance on how to approach this or what anyone has done in the past to support this capability would be much appreciated!
Hi! What did you end up doing?
I ended up making a Lockable Protocol and forked a version of SwiftyGPIO to make the I2C module open so I could subclass it and make a LockableI2cInterface subclass. While there I modified the error handling to stop the abort errors since I do not want the system to die if a sensor fails.
This is very similar to the Python library.... call the tryLock() to get access to the bus and then release the bus by issuing unlock() after completing all commands. I know there are better solutions out there, but I'm hoping this will work for this version of the design.
Any inputs would be much appreciated!
protocol Lockable {
var semaphore: DispatchSemaphore { get }
var locked: Bool { set get }
var serialQueue: DispatchQueue { get }
var waitTimeoutSeconds: Int { get }
mutating func tryLock() -> Bool
mutating func unlock() -> Void
}
extension Lockable {
mutating func tryLock() -> Bool {
if semaphore.wait(timeout: .now() + .seconds(waitTimeoutSeconds)) == .success {
locked = true
return true
} else {
return false
}
}
mutating func unlock() {
var isLocked = false
serialQueue.sync {
isLocked = locked
}
if isLocked {
locked = false
semaphore.signal()
}
}
}