Internet of Things. Behind these three little words lie thousands of use cases. Not many topics in current tech industry are as trending and innovative as this one.
We’ve pushed Swift into embedded devices…
Oh yes, we have. But hey, maybe you’re not familiar with the topic and haven’t heard of Swift at all? Well then, let me give you a quick introduction to this young and progressing programming language, because it’s well worth knowing and it can be a real blast in the future. In fact, in the world of iOS Development it already is.
Swift was introduced in June 2014 as a native development language for iOS and macOS powered devices. It was a refreshing change and a change which was necessary. Back then another language, Objective-C was a primary language in iOS Development. Objective-C was already mature and well developed, but due its origins rooting back in the 80s, unpleasant syntax and overall technical limitations it definitely needed to be replaced with something fresh.
Swift gained popularity from day one. It introduced modern language constructions like generics, optionals, type safety or rich enumerations. It also brought declarative programming to iOS. Thanks to its constant evolution and “easy to learn, hard to master” attitude, Swift quickly became one of the quickest trending languages on GitHub and brought a new wave of iOS/macOS Developers who weren’t so keen on learning something as outdated as Objective-C.
But that’s not the end of the story. In December 2015 Swift faced one of the most important challenges since its origin. It was the time when Apple announced that they’re open-sourcing Swift among with its Package Manager and set of Core Libraries including some of the goodies which are well known in the world of Apple development like Foundation, Dispatch or XCTest.
And now, since the end of 2015 developers around the world are invited to work on the evolution of the language. It was less than two years ago and since then Swift already took some significant progress and became even better language in such short period of time. But what’s also important, it was no longer a language which could be ran only on devices from Apple family. From this moment Ubuntu users were able to enjoy the brand new language as well and it opened doors for many different use cases which weren’t so easy to notice in the past.
And here’s how the story started…
Since its open sourcing in December 2015 and going cross platform, Swift took a giant step ahead and found its purpose in many different areas such as Web Development. Backend frameworks like Perfect, Kitura or Vapor are gaining more interest and popularity and are highly regarded for their modern and performant nature. We’ve also learned that Swift can be used as a tool for Machine Learning, that some first steps in bringing Swift to Android were taken and it’s also quite handy in the Internet of Things area.
With open Swift being open source, Ubuntu support and knowledge taken from our experience in iOS Development we decided that there’s nothing to lose. We’ve bought a Raspberry Pi 3, installed Ubuntu on the board and took a deep dive into GitHub to see what has been already achieved in the community of Swift ARM. With no particular expectations we decided to explore current potential of Swift in IoT, forming an internal open goal project called Embedded Swift.
The first step was a basic one. We wanted to install Swift on Raspberry Pi and make it runnable. You can find some instructions on GitHub how to do that, but in most cases you can reach for a ready-to-go solution. What I mean by that is that Swift needs to be compiled under your architecture and due to embedded boards limited processing power it takes some time. Luckily, Raspberry Pi 3 is one of the most popular boards on the planet and finding a precompiled package for your microprocessor type is not difficult.
And that’s what we did. We installed armv7-compiled version of Swift on Raspberry Pi 3 running Ubuntu Mate. Running swift -v command in the terminal produced a familiar (at least to Swift developers) output informing us about current version of language running on the device. First we tried to run a simple “Hello World” application and it was successful, as we managed to see the output. After that, the time has come to see which parts of the Swift Package are available on the Pi. With the Swift Programming Language, Swift Package Manager, Foundation and Dispatch running without problems, we immediately knew that the potential is there.
Time to build something!
For our first project we’ve bought a breadboard, couple of LEDs, resistors, jumpers and a DS18B20+ temperature sensor. With such equipment, it was quite obvious that the first scope of our research will be GPIO.
GPIO stands for General Purpose Input/Output. It is a generic interface, used by embedded boards to connect with integrated circuits or external peripherals. Accessories connected via GPIO have no predefined purpose, but they’re fully controllable by the user and can be read and written in the runtime. Raspberry Pi 3 contains 40 pins, with 26 of them being GPIO pins and the others being either ground or power pins. That actually opens a broad spectrum of possibilities for prototyping.
To make the GPIO running in Swift, we needed a tool to communicate with the pins and Umberto Raimo’s SwiftyGPIO was our preferred choice. It provides a Swift interface for communicating with GPIO pins with some predefined pin layouts for the most popular embedded boards. If you’re a Raspberry Pi, BeagleBone or Banana Pi user you’ll probably find the library very helpful, as it simplifies the development greatly.
And that’s what we did exactly. We set up the Swift Package Manager, added SwiftyGPIO to our project and used our accessories to build our first electronic circuit powered by the modern programming language from Apple. Our layout was pretty simple, with two LEDs (right and green) and temperature sensor connected to the breadboard, accompanied with two resistors and couple of jumpers to keep the flow correct. With that set up, we connected the breadboard to the Pi and configured the DS18B20+ driver to dump information about the temperature into a text file.
After that, we wrote a script reading the temperature from the file and powering on one of the two LEDs, depending on the temperature. The current temperature was also printed out to the user’s screen, both in Celsius and Fahrenheit. It was still a quite simple circuit, but hey, it was already working flawlessly and ultimately we built a digital thermometer on our own. All in Swift, so it was already exciting. But it was not only 1-wire protocol you could use for development, as SwiftyGPIO provides you with I2C and SPI interfaces or PWM signals to take your project into another level. With that in mind, and having already seen some examples of that in action, we’ve switched our focus into Bluetooth.
Remember Core Bluetooth? That sweet, approachable API Apple provided us with to make the Bluetooth development easier on their own products? Well, don’t be mistaken as it does not work on Linux, but we found something which can be perceived as a pretty good alternative. And Alsey Coleman Miller’s BluetoothLinux has just one goal - to provide the programmable Bluetooth stack for Swift on Linux.
BluetoothLinux communicates directly with Linux kernel and exposes low-level elements of the Bluetooth stack like GATT to the developer. It may sound tricky at first, but if you’re already familiar with Core Bluetooth and whole concept of communication based on services and characteristics, it means you’re familiar with GATT already. Also, working directly on the low-level parts of the stack is not always necessary due to existence of some high level APIs in the library.
One of the greatest additions to Raspberry Pi 3 (compared to the Raspbery Pi 2) was an onboard Bluetooth Low Energy module. Together with Swift and BluetoothLinux it sounded like a perfect combination. So as always, we’ve used Swift Package Manager to install the dependencies. Our first test was to set up the Pi as a beacon, as the library provides us with some examples how to do that.
The most important part of the implementation was to create an instance of Adapter class to provide appropriate information about our beacon. It included information like the unique identifier of the region, major and minor values, RSSI and ranging interval. With that set up, we started broadcasting the beacon frames and our device was quickly recognizable by iPhone and ready for communication. To sum up, bringing our new Raspberry Pi-Beacon to life was almost as simple, as writing a couple of lines in the Core Location framework to do the same on Apple devices.
But what about other Bluetooth devices? We already know they’re not only beacons but mostly Bluetooth Low Energy centrals and peripherals. As we mentioned earlier, BluetoothLinux relies on Swift implementation of the GATT protocol which includes implementation for both services and characteristics. There’s an example of GATT Server in the library files which nicely shows how to create an example device. API itself is really similar to CBMutableService and CBMutableCharacteristic classes from Core Bluetooth framework, and provides pretty much the same functionality, so it was pretty understandable for us how to run our own Swift central on Linux.
So, what have we learned so far?
Having no idea at first about the possibilities of Embedded Swift, we managed to find out that the potential is there. Apple does support the idea just partially by providing Swift binaries for Ubuntu-based systems, but making these binaries runnable on embedded devices and providing interfaces for communication with external accessories in Swift, is purely on the side of the community.
Embedded Swift was a pretty interesting project for us which gave us a nice dose of excitement, as it was challenging and required a little more focus and research than usual with the lack of official support and documentation. However, the Swift-ARM community doesn’t stop in supporting the idea and bringing it into new level with new releases of support libraries being more mature than the previous ones and new precompiled Swift binaries giving more stable API than in the past.
More posts by this author