Skip to content
sieben edited this page Dec 10, 2014 · 4 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 with 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 this 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 typically supported 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 this 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 in 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 80 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 currently defined to filter out carriage return (ASCII code 0x0D) symbols. END specifies the symbol that should cause the serial_line_process to be polled, and is currently set to 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 is typically 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 this 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 broadcasted 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 startup code initializes the LEDs library by calling leds_init() initializes the API. Any of the following functions can thereafter be used 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(). This function returns a LEDs vector of type unsigned char, in which one bit represent 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 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 set in the argument ledv. The function leds_toggle() is an alias for leds_invert(), and is only kept 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