uraimo / SwiftyGPIO

A Swift library for hardware projects on Linux/ARM boards with support for GPIOs/SPI/I2C/PWM/UART/1Wire.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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()
        }
    }
    
    
}