Write an environment sensing application

Process overview, relocation model and system call API

In this section, we're going to learn about processes (a.k.a applications) in Tock, and build our own applications in C.

Get a C application running on your board

You'll find the outline of a C application in the directory exercises/app.

Take a look at the code in main.c. So far, this application merely prints "Hello, World!".

The code uses the standard C library routine printf to compose a message using a format string and print it to the console. Let's break down what the code layers are here:

  1. printf is provided by the C standard library (implemented by newlib). It takes the format string and arguments, and generates an output string from them. To actually write the string to standard out, printf calls _write.

  2. _write (in libtock-c's sys.c) is a wrapper for actually writing to output streams (in this case, standard out a.k.a. the console). It calls the Tock-specific console writing function putnstr.

  3. putnstr(in libtock-c's console.c) is a buffers data to be written, calls putnstr_async, and acts as a synchronous wrapper, yielding until the operation is complete.

  4. Finally, putnstr_async (in libtock-c's console.c) performs the actual system calls, calling to allow, subscribe, and command to enable the kernel to access the buffer, request a callback when the write is complete, and begin the write operation respectively.

The application could accomplish all of this by invoking Tock system calls directly, but using libraries makes for a much cleaner interface and allows users to not need to know the inner workings of the OS.

Loading an application

Okay, let's build and load this simple program.

  1. Erase all other applications from the development board:

    $ tockloader erase-apps
  2. Build the application and load it (Note: tockloader install automatically searches the current working directory and its subdirectories for Tock binaries.)

     $ tockloader install --make
  3. Check that it worked:

    $ tockloader listen

    The output should look something like:

    $ tockloader listen
    No device name specified. Using default "tock"
    Using "/dev/cu.usbserial-c098e5130012 - Hail IoT Module - TockOS"
    Listening for serial output.
    Hello, World!

Creating your own application

Now that you've got a basic app working, modify it so that it continuously prints out Hello World twice per second. You'll want to use the user library's timer facilities to manage this:


You'll find the interface for timers in libtock/timer.h. The function you'll find useful today is:

#include <timer.h>
void delay_ms(uint32_t ms);

This function sleeps until the specified number of milliseconds have passed, and then returns. So we call this function "synchronous": no further code will run until the delay is complete.

Write an app that periodically samples the on-board sensors

Now that we have the ability to write applications, let's do something a little more complex. The development board you are using has several sensors on it. These sensors include a light sensor, a humidity sensor, and a temperature sensor. Each sensing medium can be accessed separately via the Tock user library. We'll just be using the light and temperature for this exercise.


The interface in libtock/ambient_light.h is used to measure ambient light conditions in lux. imix uses the ISL29035 sensor, but the userland library is abstracted from the details of particular sensors. It contains the function:

#include <ambient_light.h>
int ambient_light_read_intensity_sync(int* lux);

Note that the light reading is written to the location passed as an argument, and the function returns non-zero in the case of an error.


The interface in libtock/temperature.h is used to measure ambient temperature in degrees Celsius, times 100. imix uses the SI7021 sensor. It contains the function:

#include <temperature.h>
int temperature_read_sync(int* temperature);

Again, this function returns non-zero in the case of an error.

Read sensors in a Tock application

Using the example program you're working on, write an application that reads all of the sensors on your development board and reports their readings over the serial port.

As a bonus, experiment with toggling an LED when readings are above or below a certain threshold:


The interface in libtock/led.h is used to control lights on Tock boards. On the Hail board, there are three LEDs which can be controlled: Red, Blue, and Green. The functions in the LED module are:

#include <led.h>
int led_count(void);

Which returns the number of LEDs available on the board.

int led_on(int led_num);

Which turns an LED on, accessed by its number.

int led_off(int led_num);

Which turns an LED off, accessed by its number.

int led_toggle(int led_num);

Which toggles the state of an LED, accessed by its number.