In this section, we're going to learn about processes (a.k.a applications) in Tock, and build our own applications in C.
You'll find the outline of a C application in the directory
Take a look at the code in
main.c. So far, this application merely prints
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:
printfis 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,
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
console.c) is a buffers data to be written, calls
putnstr_async, and acts as a synchronous wrapper, yielding until the operation is complete.
console.c) performs the actual system calls, calling to
commandto 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.
Okay, let's build and load this simple program.
Erase all other applications from the development board:
$ tockloader erase-apps
Build the application and load it (Note:
tockloader installautomatically searches the current working directory and its subdirectories for Tock binaries.)
$ tockloader install --make
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!
Now that you've got a basic app working, modify it so that it continuously
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
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.
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
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
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.
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.