Sensinode Reference Nanostack v1.0.1
Sensinode Reference Nanostack v1.0.1
NanoStack Reference
v1.0.1
1/11
NanoStack Reference
Table of Contents
1 Introduction.....................................................................................................................................................3 2 NanoStack Configuration Files.......................................................................................................................3 2.1 FreeRTOS configuration.........................................................................................................................3 2.2 NanoStack configuration.........................................................................................................................3 3 Starting NanoStack.........................................................................................................................................5 4 NanoStack Communication Basics.................................................................................................................7 4.1 Creating a socket.....................................................................................................................................7 4.2 Ports.........................................................................................................................................................7 4.3 Address structure ....................................................................................................................................7 4.4 Receiving.................................................................................................................................................8 4.5 Sending....................................................................................................................................................8 4.6 Control Sockets.......................................................................................................................................9 4.7 Notes on application design....................................................................................................................9 5 NanoStack Run-time Configuration.............................................................................................................10 5.1 Function APIs........................................................................................................................................10 5.2 Routing..................................................................................................................................................10 5.3 Routing errors........................................................................................................................................11 6 Port-specific notes.........................................................................................................................................11 6.1 GCC compiler notes..............................................................................................................................11 6.2 SDCC compiler notes............................................................................................................................11
v1.0.1
2/11
NanoStack Reference
Introduction
1 Introduction
This document is intended to help NanoStack software developer in writing applications and getting NanoStack configured to suit their application requirements. This reference covers NanoStack configuration, FreeRTOS configuration, stack initialization, socket API usage, and run-time configuration. Please also see the Doxygen reference in /NanoStack/Docs for more detailed information on function parameters and data structures.
2.1
FreeRTOS configuration
The FreeRTOS configuration file is named FreeRTOSConfig.h. It is located in the application directory e.g. /NanoStack/Example/micro_example_u100. Table 1: FreeRTOS relevant parameters.
Parameter configCPU_CLOCK_HZ configTICK_RATE_HZ configMINIMAL_STACK_SIZE configTOTAL_HEAP_SIZE Description System clock frequency in Hz System timer tick resolution in Hz Stack minimum size in bytes Size of dynamic memory area Options Default Platform dep. 1000 200 RAM size - 2kB
2.2
NanoStack configuration
The NanoStack configuration file is named app.rules, and is located in the application directory along with Makefile, FreeRTOSConfig.h etc. The app.rules file has defaults for all parameters except MAC_MODE, which always must be set. Binary options use 1 for on and 0 for off. Table 2: General configuration parameters.
Parameter STACK_BUFFERS_MAX STACK_BUFFERS_MIN SOCKETS_MAX HAVE_DEBUG HAVE_EVENT_TIMERS HAVE_POWERSAVE Description Upper limit for allocated buffers Minimum amount of allocated buffers Amount of available sockets Enable debugging library on UART Number of available event timers Turn on automatic powersave features (experimental) Options Max 10 Min 4 6 4 4 1 8 0 Default
v1.0.1
3/11
NanoStack Reference
1 7
4/11
NanoStack Reference
Parameter DEBUG_RX_LEN DEBUG_TX_LEN Description Size of UART RX buffer Size of UART TX buffer
STACK_DEBUG SOCKET_DEBUG CIPV6_DEBUG CIPV6_CONTROL_DEBUG CUDP_DEBUG ROUTING_DEBUG NWK_CONFIG_DEBUG RF_802_15_4_DEBUG CC2420_DEBUG CC2420_DEBUG_RSSI B1W_DEBUG
0 0 0 0 0 0 0 0 0 0 0
Selecting many tracing sections simultaneously may affect system timings and severely compromise correct protocol functionality.
3 Starting NanoStack
An application based on NanoStack is started in 4 phases:
HW initialization Creating initial tasks Starting the FreeRTOS scheduler Starting NanoStack
HW initialization is performed by the bus_init() function, which is included in /Platform under the correct platform directory. The function typically contains only essential initialization steps, such as configuring the system clock source. Additional initialization may be performed in the main() function in cases where the application does not do all its initialization via driver modules. If the debug library is used, the debug_init(speed) call should be done right after calling bus_init() in the main() function. The main() function is also responsible of initial application task creation. Platform hardware initialization:
bus_init();
5/11
NanoStack Reference
Starting NanoStack
NULL );
In this phase execution continues in your application task (or the task with the highest priority, in case you created multiple tasks in main() function). NanoStack is started by the stack_start() function. This function initializes all resources required by the protocol stack core and the RF driver. No NanoStack API calls may be called before the stack_start() function has been executed. The function must be executed inside the application task. If NULL is passed as a parameter stack_start() uses default values for the current MAC mode defined in app.rules.
typedef struct { log_dev_type_t uint8_t uint8_t uint8_t uint8_t uint8_t uint8_t } stack_init_t; type; channel; pan_id[2]; short_address[2]; use_sw_mac; mac_address[8]; pending_ttl_time;
The type field specifies one of the following operation modes: AD_HOC_DEVICE BEACON_ENABLE_CLIENT BEACON_ENABLE_COORDINATOR BEACON_ENABLE_GATEWAY Device in ad-hoc mode A client in a coordinated network Network coordinator/router Gateway device, gathering data from coordinators
Valid values for channel are 11-26. The PAN ID and MAC address fields are used to setdevice address for coordinator and gateway devices. Set use_sw_mac to 0 and the MAC address is set automatically, or 1 to set it manually. The pending_ttl_time specifies the time a coordinator will store a data packet for a child device. The time is in multiples of 15 seconds, the default value is 5. A task, such as the application task, runs in an endless for loop. It is important that this for loop spends most of its time sleeping so that the scheduler can handle other tasks. Sleeping occurs when blocking on a queue or semaphore (socket_read() blocks on a queue), or by explicitly calling vTaskDelay() or vTaskDelayUntil(). Simple example skeleton of an application task:
static void application_task( void *pvParameters ) { socket_t *app_socket; sockaddr_t sa; buffer_t *buf = 0; debug_init(115200); /*debug functions may be called now*/ debug("Start NanoStack.\r\n"); if(stack_start(NULL)==START_SUCCESS) { debug("Start OK.\r\n"); } app_socket = socket(MODULE_CUDP, 0); sa.port = 253; socket_bind(app_socket, &sa); /*listen to port 253*/ for(;;) { /*wait for packets, timeout 1 second*/ buf = socket_read(app_socket, 1000); if (buf) { /*data received*/
v1.0.1
6/11
NanoStack Reference
...process data... socket_buffer_free(buf); } } }
Starting NanoStack
/*free buffer*/
See /Examples/micro_beacon_gateway for an example of manually setting all the start_init structure for use with a FFD device acting as a gateway.
4.1
Creating a socket
A socket is created by the socket() function call which has 2 parameters: 1. Protocol type: what protocol this socket is going to use, e.g. MODULE_CUDP 2. Handler function: if you prefer implementing reception in a callback fashion, insert your handler function pointer here. A null pointer means callback is not used. After the socket has been created, you can specify additional protocol multiplexer (port number) by calling socket_bind(), again with 2 parameters: 1. Pointer to your socket (returned by call to socket() previously) 2. Pointer to a sockaddr_t struct, containing the port number in the port field If you are about to use your socket only for sending or expect your peer to respond with your address (most client-type applications), calling bind is not necessary. A random port will be allocated when first packet is sent.
4.2
Ports
Port ranges in NanoStack are used identically to ports in any TCP/IP stack. When using UDP in uncompressed mode, the 16-bit port range from 5-65536. When using UDP in compressed mode ports are restricted to a 4-bit range from 61616-61631 as in the 6LoWPAN specification. Ports 1-4 are reserved for use with control sockets.
4.3
Address structure
The address structure used by the Socket API is called sockaddr_t and includes the following fields:
typedef struct { addrtype_t address_t uint16_t } sockaddr_t; addr_type; address; port; /*!< Type of address */ /*!< Source or destination address */ /*!< Source or destination port */
The addr_type field defines what kind of address in included, and port field is defined above. The following address types are defined. ADDR_NONE ADDR_802_15_4_LONG ADDR_802_15_4_SHORT
v1.0.1
7/11
NanoStack Reference
16-bit PAN with 16-bit 802.15.4 address 16-bit PAN with 64-bit 802.15.4 address 8-bit address in octet 0 16-bit PAN-id Attribute-based data-centric query Broadcast address Coordinator address only for Beacon enable mode
4.4
Receiving
Receiving data from a socket has 2 options: 1. using socket_read() 2. using a callback function, given as a parameter to socket() The socket_read() function returns a pointer to a buffer_t structure (data received) or 0 (timed out). The function has 2 parameters: 1. Pointer to your socket (returned by call to socket() previously) 2. Timeout value in milliseconds (a value of 0 can be used to poll the socket) All received buffers must be freed using socket_buffer_free() once the data has been handled. The buffer may also be re-used for sending data: in this case the buffer must not be freed. In case of callback reception, the user has to implement a handler function with the following return type and parameters:
portCHAR my_handler_function_name(buffer_t *buffer)
The handler function should never block. The function is called from the protocol stack task: if the function blocks, the protocol core (and drivers) will be halted for that time.
4.5
Sending
Data is sent via the socket using socket_sendto(). The function returns pdTRUE on success and pdFALSE on failure. In case of failure, the application may opt to resend the buffer (after some delay, preferably) or just free the buffer. In case of success, the buffer will be freed by the RF driver after packet has been sent. Do not try to free the buffer yourself after re-sending. Example of sending:
buffer_t *buffer = socket_buffer_get(socket, timeout); int retry = 0; sockaddr_t dest_address; if (buffer) {
v1.0.1
8/11
NanoStack Reference
<code fills in the address data> <code creates the data packet> while ( (socket_sendto(socket, &dest_address, buffer) == pdFALSE) && (retry++ < 3)) { vTaskDelay(5); /*wait for 5 ticks on failure*/ } if (retry >= 3) socket_buffer_free(buffer); /*sending failed*/
4.6
Control Sockets
Sockets are also used to send and receive control messages from protocol modules in NanoStack. A control socket uses the module identifier (e.g. MODULE_ICMP) to send or receive messages with a module. In addition ports (1-4) are reserved for use with control sockets. Use a matching socket type and port define with control sockets. Control socket port definitions: ICMP_CTRL_PORT CUDP_CTRL_PORT CIPV6_CTRL_PORT MAC_CTRL_PORT 1 2 3 4
Modules with a control interface: MODULE_ICMP, MODULE_CUDP, MODULE_CIPV6, MODULE_MAC Example of binding to a control socket:
sockaddr_t control_address = { ADDR_NONE, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ICMP_CTRL_PORT }; task() { ... socket_t *icmp_control=0; icmp_control = socket(MODULE_ICMP, 0); if (icmp_control) { if (socket_bind(icmp_control, &control_address)!=pdTRUE) debug("Bind fail icmp.\r\n"); } }
4.7
Do not declare too many variables inside the application main function. Since these variables will be present always during program execution, it is easier to estimate RAM usage when variables are declared as static variables. This reduces the application stack size and the linker will give you an error if you run out of RAM. In this case you can adjust the size of the dynamic RAM area to give room for your static variables. This significantly simplifies application development. Another way of simplifying RAM management is to allocate buffers using socket_buffer_get() for larger data structures that are only required temporarily.
v1.0.1
9/11
NanoStack Reference
A task, such as the application task, runs in an endless for loop. It is important that this for loop spends most of its time sleeping so that the scheduler can handle other tasks. Sleeping occurs when blocking on a queue or semaphore (socket_read() blocks on a queue), or by explicitly calling vTaskDelay() or vTaskDelayUntil().
5.1
Function APIs
For cUDP:
cudp_compress_mode(mode) (1=on, 0=off)
Compression is enabled by default for both IPv6 and UDP modules, and does not need to be manually set. MAC module configuration API: Get coordinator address (on client)
portCHAR get_coord_address(sockaddr_t *address)
5.2
Routing
The cIPv6 NanoMesh routing module is configured using a control socket. Control socket message types are defined in control_message.h. A control socket is created by calling socket(MODULE_CIPV6, handler). The socket has the following message types:
v1.0.1
10/11
NanoStack Reference
Router_DISCOVER: initiates gateway discovery procedure Router_DISCOVER_RESPONSE: this contains the results of gateway discovery Router_ADVERT_SEND: the gateway advertises itself to the network using this message.
5.3
Routing errors
The ICMP module is responsible for handling routing errors: a control socket is created by calling socket(MODULE_ICMP, handler). The socket has the following message types: ICMP_ERROR: the ID field contains the error type. The ID BROKEN_LINK returns the address of the peer that could not be reached. In the current implementation the packet data is lost: the coordinator should proxy the data for 200 milliseconds to allow resending. This will be fixed in the next release: the error packet will contain also the application data within the data field of the ICMP message. This data may then be re-sent by the application.
6 Port-specific notes
This chapter lists options available in only specific compiler/platform environments.
6.1
1. All GCC ports should be configured so that the compiler generates re-entrant functions. Otherwise any code that is called from multiple tasks will eventually fail.
6.2
1. Because of SDCC and 8051 architecture limitations, the heavy use of pointers in FreeRTOS makes the code size generated by SDCC large. 64 kB of ROM is available for use on NanoModule N120, which currently allows for basic ad-hoc MAC and 6lowpan/UDP/ICMP modules to be used with ample space for application code. A patch for using all 128 kB with SDCC is also now available, although not part of the core releases yet. This issue will be fixed with a new scheduler in NanoStack v2.x. 2. Interrupts need special consideration when using SDCC. When creating an interrupt in the application, you must create a header file included in the application (main.c) with a prototype of the interrupt. Otherwise the interrupt vector isn't registered with SDCC.
v1.0.1
11/11