Skip to content

Input and output

Benoît Thébaudeau edited this page Sep 23, 2019 · 9 revisions

The type of I/O devices available to the programmer is highly dependent on the platform in use. Contiki provides two basic interfaces that most platforms share: serial I/O and LEDs. Serial output is supported by the standard C library API for printing; whereas, serial input depends on a Contiki-specific mechanism. The LEDs API, on the other hand, is an abstraction for using LEDs portably. Platforms may implement that API as a stub if no LEDs are available.

Table of Contents

Serial Communication

The serial I/O API

int printf(const char *format, ...); /* Print a string according to a format. */
int putchar(int c); /* Print a single character. */

Printing

printf() is supported typically by linking in the function from the standard C library provided by the used compiler suite. We refer the reader to the ISO C standard for a complete description of how that function can be used.

Note that some embedded C libraries implement printf without floating point support. printf() simply calls putchar() after formatting an output string. putchar() has a hardware-dependent implementation that directs one byte at-a-time to the serial port.

Receiving

Contiki has a generic interface for line-based serial communication, specified in core/dev/serial-line.h. serial_line_init() needs to be called before using this unit, so that the serial_line_process and ring buffer required can be initialized. Note: process_init() must be called before calling serial_line_init() so that the serial_line_process is added to the process_list.

An interrupt is generated when a character is ready to be read from the serial port. The interrupt handler calls serial_line_input_byte(), which buffers data until a new-line symbol is received. If we have a complete line, we broadcast an event to all processes.

serial_line_input_byte() is a callback function that receives input bytes from the serial drivers in several Contiki platforms. The function fills a local buffer until a line break is received; after which, it polls the serial_line_process. The local buffer size for serial lines is configurable through the parameter SERIAL_LINE_CONF_BUFSIZE; and, defaults to 128 bytes. If longer lines are received, only (SERIAL_LINE_CONF_BUFSIZE - 1) bytes and a nil byte will be passed on to serial_line_process. The serial_line_process broadcasts a serial_line_event_message to all processes in the system, along with the received string (pointed to by the event data).

The serial line driver has two macros defined, to control the input. IGNORE_CHAR(c) provides a simple filter that returns true if character c should not be put into the local serial buffer. It is defined currently to filter out carriage return (ASCII code 0x0D) symbols. END specifies the symbol that should cause the serial_line_process to be polled; and, currently is set to the line break (ASCII code 0x0A) symbol.

In platforms that have processors capable of going into low-power mode, serial_line_input_byte() can indicate whether the CPU should stay awake for further processing, or not. Since the function typically is called from an interrupt handler in a serial driver, it might have been called from low-power mode. Thus, if further processing is necessary, the hardware-dependent part of Contiki must ensure that the CPU moves into active mode, in order to be able to schedule the execution for other processes that might be interested in a serial line. For that purpose, all single-byte serial input functions in Contiki, including serial_line_input_byte(), must indicate whether the system should continue sleeping or not. A non-zero return value specifies that the CPU should move into active mode; whereas, a zero return value tells the driver that the system can continue sleeping in low-power mode.

We show how to receive serial lines below.

Serial line events are broadcast to all processes when the underlying device driver has received a line break. The event data contains a string with the line of data.

 #include "contiki.h"
 #include "dev/serial-line.h"
 #include <stdio.h>
 
 PROCESS(test_serial, "Serial line test process");
 AUTOSTART_PROCESSES(&test_serial);
 
 PROCESS_THREAD(test_serial, ev, data)
 {
   PROCESS_BEGIN();
 
   for(;;) {
     PROCESS_YIELD();
     if(ev == serial_line_event_message) {
       printf("received line: %s\n", (char *)data);
     }
   }
   PROCESS_END();
 }

LEDs

LEDs are a simple but important tool to communicate with users, or to debug programs. The LEDs API is shown below. The platform start-up code initializes the LEDs library by calling leds_init(). Any of the following functions can be used thereafter by either the system or applications.

The LEDs API

void leds_init(void); /* Initialize the LEDs driver. */
unsigned char leds_get(void); /* Get the status of a LED. */
void leds_on(unsigned char ledv); /* Turn on a set of LEDs. */
void leds_off(unsigned char ledv); /* Turn off a set of LEDs. */
void leds_toggle(unsigned char ledv); /* Toggle a set of LEDs. */
void leds_invert(unsigned char ledv); /* Toggle a set of LEDs. */

The set of LEDs that are on can be retrieved by calling leds_get(). That function returns a LEDs vector of type unsigned char, in which one bit represents one LED. The mapping between LEDs and the bits in a LED vector is platform-independent because of the set of macros specified below. If a platform has a superset of the defined colors, the LEDs vector must include a portion which is platform-defined.

LED identifiers for use in LED vectors.

 #define LEDS_GREEN                    1
 #define LEDS_YELLOW                   2
 #define LEDS_RED                      4
 #define LEDS_ALL                      7

leds_on() takes a LEDs vector argument, ledv, and switches on the LEDs that are set in the vector. The leds_off() function switches off the LEDs marked in the argument ledv. leds_invert() inverts the current status of the LEDs that are set in the argument ledv. The function leds_toggle() is an alias for leds_invert(); and, is kept only for backward compatibility.

Conclusions

Contiki provides two generic programming interfaces for input and output. The serial communication uses standard C functions for output, and Contiki-specific functions for input. The LEDs library is entirely Contiki-specific; and, is supported on most platforms, either as an implementation using real hardware or as a set of stub functions.

Clone this wiki locally