Detect Serial Devices in Swift

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.

1. Setting up Xcode

Start Xcode, and create a new Command Line project for OS X.

Start Project

Start Project Name

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.

Hello World

The Serial Device Discover Function

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
}

2. The Serial Device Discover Function

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 Main Example

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

Detect Devices

3. Downloads

You can download the code from GitHub: https://github.com/bjarnoldus/swift-detect-serial