This tutorial explains how you can automatically detect serial devices using Swift on OS X. Mac OS X automatically enumerates serial devices connected to a Mac. This functionality is provided by the I/O Kit. These devices are categorized, so you can easily filter for the devices where you are interested in. We guide you how to use this mechanism in setting up a simple implementation.
Start Xcode, and create a new Command Line project for OS X.
Add the following imports to main.swift:
import IOKit
import IOKit.serial
Run the code program, and “Hello World” should be printed on your screen. We are now ready for detecting serial devices.
The function findSerialDevices does the actual discovery of serial devices. It calls the kernel to match against the service property of serial device. The deviceType can be used to filter the results for more specific devices, like modems. The seriapPortIterator is a pointer to the iterator, which findSerialDevices will set. The return value is a kernel return type, and may contain an error message.
func findSerialDevices(deviceType: String, inout serialPortIterator: io_iterator_t ) -> kern_return_t {
var result: kern_return_t = KERN_FAILURE
var classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue).takeUnretainedValue()
var classesToMatchDict = (classesToMatch as NSDictionary)
as Dictionary<String, AnyObject>
classesToMatchDict[kIOSerialBSDTypeKey] = deviceType
let classesToMatchCFDictRef = (classesToMatchDict as NSDictionary) as CFDictionaryRef
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatchCFDictRef, &serialPortIterator);
return result
}
The printSerialPaths function shows how an returned iterator of findSerialDevices can be used. This function print all the discovered callout paths to the output screen. In real applications this code can be adapted to return a list of discovered devices.
func printSerialPaths(portIterator: io_iterator_t) {
var serialService: io_object_t
do {
serialService = IOIteratorNext(portIterator)
if (serialService != 0) {
let key: CFString! = "IOCalloutDevice"
let bsdPathAsCFtring: AnyObject? =
IORegistryEntryCreateCFProperty(serialService, key, kCFAllocatorDefault, 0).takeUnretainedValue()
var bsdPath = bsdPathAsCFtring as String?
if let path = bsdPath {
println(path)
}
}
} while serialService != 0;
}
The previous functions can be called in the following order. The portIterator is an empty variable used as pointer for the iterator. This example searches for all serial devices by applying kIOSerialBSDAllTypes, other options are:
kIOSerialBSDRS232Type - Generic Serial RS-232 devices
kIOSerialBSDModemType - Devices enumerated as modem
var portIterator: io_iterator_t = 0
let kernResult = findSerialDevices(kIOSerialBSDAllTypes, &portIterator)
if kernResult == KERN_SUCCESS {
printSerialPaths(portIterator)
}
You can download the code from GitHub: https://github.com/bjarnoldus/swift-detect-serial