Craft At WillowTree Logo
Content for craftspeople. By the craftspeople at WillowTree.
Engineering

Raspberry Pi GPIO with Kotlin Native

Kotlin has been getting a lot of attention as an officially supported language on the Android platform. While it works fantastically there and on the JVM, it does target other platforms: namely the web with KotlinJS and native platforms via Kotlin native. If you aren’t familiar, the Kotlin native (fondly referred to as Konan) toolchain expands the Kotlin compiler with the ability to output native executables that don’t need to run inside of a VM. If you are interested in learning more about the platform, I go into quite a bit of detail in a previous related post: A look into Kotlin native.

While Konan is still in its early access preview stages, it’s already capable of targeting quite a few platforms not the least of which is the Raspberry Pi 2 and 3. In this blog post, I’ll be illustrating the process involved in using native libraries with Konan, by using Konan to access the raspberry pi’s GPIO using WiringPi.

Enter WiringPi

WiringPi is a simple abstraction for pin based GPIO access. A lot of its APIs are designed to mimic the Arduino Wiring system, so anyone with Arduino experience will feel right at home using WiringPi.

Before getting started it’s important to note that as at the time of this writing, you can only cross compile kotlin native code for the raspberry pi on a linux OS.

This is a limitation of the compiler which is expected to be resolved in the future. If you are working on a different platform you can choose to follow along in a virtual machine.

We’ll need to build WiringPi from source as well as statically link and archive the resulting native objects. Thankfully, the included Makefile does this for us.

This step needs to be done on the Raspberry Pi because the resulting objects are compiled specifically for its architecture.

While it is possible to cross compile for the device, it’s beyond the scope of this post.

git clone https://github.com/WiringPi/WiringPi.git
cd WiringPi/wiringPi
make static

The compiled output generates libwiringPi.a, which is an archive containing the native library.

Next we need to come up with a *.def definitions file for our library. This tells Konan which headers to include while generating method stubs for use in interacting with our native library. This means that we’ll have to copy the header files into our project. We can define these in a file called wiringPi.def.

headers = wiringPi.h wiringPiI2C.h wiringPiSPI.h

Next we need to put together our project’s build script. We’ll be using Gradle. Here’s the entire build script to get started.

buildscript {
    repositories {
        mavenCentral()
        maven {
            url  "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
        }
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:0.3"
    }
}

apply plugin: 'konan'

konanInterop {
    wiringPi {
        defFile 'wiringPi.def'
        includeDirs 'src/include/'
        linkerOpts '-lwiringPi -Lsrc/include/'
        target 'raspberrypi'
    }
}

konanArtifacts {
    ktpi {
        inputFiles fileTree('src/main/')
        useInterop 'wiringPi'
        target 'raspberrypi'
    }
}

Now let’s break down the important bits. Here we are defining a konanInterop. This essentially tells Konan that we plan on including some native libraries and headers.

konanInterop {
    wiringPi {
        defFile 'wiringPi.def'
        includeDirs 'src/include/'
        linkerOpts '-lwiringPi -Lsrc/include/'
        target 'raspberrypi'
    }
}

Here we are defining an interim called wiringPi and pointing it at the wiringPi.def file that we defined earlier. We’re also adding the src/include/ directory to search for header files using the includeDirs property.

In order to link to the wiringPi library we just generated, we use the linkerOpts property.

linkerOpts '-lwiringPi -Lsrc/include/'

The -l flag is used to tell it to link to libwiringPi.a note the omission of the lib prefix. The -L flag is used to add src/include/ to the search path.

In order to generate an executable artifact from our source we have to define konanArtifacts.

konanArtifacts {
    ktpi {
        inputFiles fileTree('src/main/')
        useInterop 'wiringPi'
        target 'raspberrypi'
    }
}

In this example we’re defining ktpi as our build artifact and including the wiringPi interop as well as setting the 'raspberrypi' as the target architecture. We’re also setting our src/main/ as the input sources folder for our build.

We are finally ready to write code. Here’s the the source for a sample blink application that simply turns an LED on and off indefinitely.

import wiringPi.*
import kotlinx.cinterop.*

val LED = 0

fun main(args: Array<String>) {
    println("Kotlin native wiringPi blink")

    wiringPiSetup()
    pinMode(LED, OUTPUT)

    while (true) {
        digitalWrite(LED, HIGH)
        delay(500)
        digitalWrite(LED, LOW)
        delay(500)
    }
}

First we import the generated method stubs as well as the interop library. This is just boilerplate for stuff we are going to want to do later.

Next we define the pin number for the gpio pin we plan to use. In this case I selected pin 0 based on the simplified WiringPi pin numbering system. For a full description of the pin out as well as alternative pin numbering schemes, I recommend taking reading through the official documentation.

The main function is pretty self explanatory, we invoke wiringPiSetup() which is required before using any of the functionality in the library. Then register our gpio pin as output using pinMode(LED, OUTPUT) like we would on the Arduino.

Finally we set up an infinite loop where we toggle our pin between the high and low states using digitalWrite.

We simply run the gradle build command to build and then execute the generated *.kexe artifact.

./gradlew build
./build/konan/bin/ktpi/ktpi.kexe

The complete sample project is available on GitHub here.

Conclusion

Kotlin native is shaping up to be a great alternative to writing code targeting native platforms with its most attractive feature being its interoperability with C. We’ve explored taking advantage of native libraries to build native apps targeting the raspberry pi. While there is a bit of setup involved, It’s really easy to work with.

Table of Contents
Nish Tahir

Recent Articles