SerialSwift
makes communicating with your Serial Peripherals on MacOS trivial.
Better still, SerialSwift
is designed to be fundamnetally Observable and Event-Driven, making it easier than ever before to consume information coming into your application from your external Serial peripheral(s).
SerialSwift
is built on top of a number of packages:
ThreadSafeSwift
from ourselves at Flowduino is used to ensure Thread-Safety throughout the libraryObservable
from ourselves at Flowduino is used to provide protocol-conformance Observer Pattern support throughout the libraryEventDrivenSwift
from ourselves at Flowduino is used to emit relevant and extremely high-performance Events for every Serial Event your Peripherals generate.ORSSerialPort
from Armadsen is used to actually interface with your Serial Peripherals.
In this way, SerialSwift
can be integrated into your code in any way you prefer, making it extremely versatile.
Select File
-> Swift Packages
-> Add Package Dependency
and enter https://github.com/Flowduino/SerialSwift.git
You can use SerialSwift
as a Package Dependency in your own Packages' Package.swift
file:
let package = Package(
//...
dependencies: [
.package(
url: "https://github.com/Flowduino/SerialSwift.git",
.upToNextMajor(from: "1.0.0")
),
],
//...
)
From there, refer to SerialSwift
as a "target dependency" in any of your package's targets that need it.
targets: [
.target(
name: "YourLibrary",
dependencies: [
"SerialSwift",
],
//...
),
//...
]
You can then do import SerialSwift
in any code that requires it.
Here are some quick and easy usage examples for the features provided by SerialSwift
:
You can create an instance of SerialSwift
per Peripheral as easily as this:
var mySerialDevice = Serial["/dev/cu.myserialdevice", .baud9600]
You would, of course, substitute both parameters in the above example with (firstly) the path to your Serial device, followed by (secondly) the Baud Rate your Serial Device uses.
It is recommended that you retain a reference to your Serialable
object somewhere globally in your application (such as on the Environment
of your application, or as a Singleton). This is because, from the moment you connect to your Serial peripheral, it will begin emitting Events that you can consume anywhere in your application... as demonstrated below.
Now that you have connected to your Serial device, the following Events will be emitted universally throughout your application, and can be consumed from anywhere in your code.
If you need to perform a specific operation any time your connection to your Serial device closes, you can do so simply from anywhere in your code:
SerialPortClosedEvent.addListener(self) { (event: SerialPortClosedEvent, priority) in
/**
Your code goes in here!
Properties available to you:
`event.refTime` = the precise "Mach Time" at which the Serial Port closed
`event.serial` = A reference to the Serial device which triggered the Event.
You can use `if ObjectIdentifier(event.serial) != ObjectIdentifier(mySerialDevice) { return }` to ensure you're only acting on Events emitted by a specific Serial device
*/
}
If you need to perform a specific operation any time your Serial device sends Data to your computer, you can do so simply from anywhere in your code:
SerialPortDataReceivedEvent.addListener(self) { (event: SerialPortDataReceivedEvent, priority) in
/**
Your code goes in here!
Properties available to you:
`event.refTime` = the precise "Mach Time" at which the Serial Port closed
`event.serial` = A reference to the Serial device which triggered the Event.
`event.data` = The actual `Data` your Serial device sent to your computer.
You can use `if ObjectIdentifier(event.serial) != ObjectIdentifier(mySerialDevice) { return }` to ensure you're only acting on Events emitted by a specific Serial device
*/
}
If you need to perform a specific operation any time your Serial device encounters an Error, you can do so simply from anywhere in your code:
SerialPortErrorEvent.addListener(self) { (event: SerialPortErrorEvent, priority) in
/**
Your code goes in here!
Properties available to you:
`event.refTime` = the precise "Mach Time" at which the Serial Port closed
`event.serial` = A reference to the Serial device which triggered the Event.
`event.error` = The actual `Error` your Serial device encountered.
You can use `if ObjectIdentifier(event.serial) != ObjectIdentifier(mySerialDevice) { return }` to ensure you're only acting on Events emitted by a specific Serial device
*/
}
If you need to perform a specific operation any time your Serial device establishes a connection with your Computer, you can do so simply from anywhere in your code:
SerialPortOpenedEvent.addListener(self) { (event: SerialPortOpenedEvent, priority) in
/**
Your code goes in here!
Properties available to you:
`event.refTime` = the precise "Mach Time" at which the Serial Port closed
`event.serial` = A reference to the Serial device which triggered the Event.
You can use `if ObjectIdentifier(event.serial) != ObjectIdentifier(mySerialDevice) { return }` to ensure you're only acting on Events emitted by a specific Serial device
*/
}
If you need to perform a specific operation any time your Serial device disconnects from your Computer, you can do so simply from anywhere in your code:
SerialPortRemovedEvent.addListener(self) { (event: SerialPortRemovedEvent, priority) in
/**
Your code goes in here!
Properties available to you:
`event.refTime` = the precise "Mach Time" at which the Serial Port closed
`event.serial` = A reference to the Serial device which triggered the Event.
You can use `if ObjectIdentifier(event.serial) != ObjectIdentifier(mySerialDevice) { return }` to ensure you're only acting on Events emitted by a specific Serial device
*/
}
SerialSwift
is available under the MIT license. See the LICENSE file for more info.
If you require additional support, or would like to discuss SerialSwift
, Swift, or any other topics related to Flowduino, you can join us on Discord.