How to Use the C Library

The

SmartMesh C Library

 is designed so you can drop the sm_clib/ directory without modification into your application.  You are free to modify it to suit your needs, however we recommend you avoid changing the contents of the sm_clib/ directory, as this will allow you to easily replace it with future revisions.

There are two sample applications packaged with the 

SmartMesh C Library

:

  • The mote application Triangle2Manager, which joins a mote to the network and sends triangle waveform data to the manager
  • The manager application MoteBlink, which sends commands downstream from the manager to the motes, blinking the INDICATOR_0 LED on a DC9003 mote running in Master mode. 

The behavior of the examples is covered in the Examples section.  The examples have been ported to the Arduino Due and the MSP430FR4133 LaunchPad.  Porting the

SmartMesh C Library

 involves implementing some functions that are specific to the hardware platform (and possibly OS/RTOS) you will be using. Details for porting to other platforms are found in the Porting To Your Hardware section. 

Overview

The primary C Library interface is through the functions defined in the device's header file, e.g. dn_ipmg.h or dn_ipmt.h

Initialization of the interface must be performed first using the appropriate init function, which also registers callbacks for connection status, API responses, and notifications. The connection to the device is performed through the initiateConnect function. Following the successful completion of the initiateConnect and a status callback indicating the connection is established, API functions can be performed. 

All callbacks are performed in the context of the RX handler, which holds a lock for managing the state of the API protocol.  

The application must not call API functions from within a callback function. 


Driving the Mote State Machine

We focus here on the mote – the manager does not need to be driven through the same state machine. 

There are a number of steps your application must take to have the mote join a network and be ready for you to send data. These steps are outlined in the SmartMesh IP Application Note "Data Publishing for SmartMesh IP" (there is an equivalent app note for SmartMesh WirelessHART).  The app note focuses on the bytes exchanged, but the

SmartMesh C Library

 handles the conversion of API commands into the raw bytes shown.  The 

SmartMesh C Library

uses similar naming to the SmartMesh IP Mote Serial API Guide - e.g. setParameter<networkId> as described in the Serial API Guide is equivalent to dn_ipmt_setParameter_networkId().  

Commands in the

SmartMesh C Library

are called in a way that differs slightly from they way they are documented in the SmartMesh IP Mote Serial API Guide.  In the Serial API guide, there is a generic command for getting/setting parameters - e.g. setParameter<networkId> takes a parameter ID (here networkId) as the first argument.  The 

SmartMesh C Library

 handles this for you - the set/get operation for each parameter is its own function.


The

SmartMesh C Library

 examples use a Finite State Machine (FSM) to drive the mote through the necessary steps. The FSM acts like a big while(1) loop - the code moves from state to state such that main() never exits. Using an FSM is a design choice - many other architectures are possible. The FSM uses the following states:

  • Set up the serial interface

The examples start by calling dn_ipmt_init() - it takes pointers to callback functions for notifications and for API responses, as well as a pointer to a buffer for receiving notifications. It eventually calls the dn_uart_init() function you provide to initialize your UART.  When a byte is received on the UART (you may need to provide a ISR for UART reception) it is appended to an incoming HDLC buffer and eventually passed to a reply or notification callback function. 

  • Acknowledge the mote boot event

The

SmartMesh C Library

 handles acknowledging notifications, including the Event notification - boot is the first event, but other events are generated as the mote joins, gets a service, etc. When notifications are received, the callback function passed in dn_ipmt_init() is invoked.  dn_ipmt_notif_cb() in the examples only handles a small subset of the possible notifications the mote could generate - it looks at the state reported in an Event notification, and either calls getParameter<moteStatus> if the mote is IDLE (i.e. the mote just booted), or getServiceInfo if the mote is OPERATIONAL.

  • Perform pre-join mote configuration

For SmartMesh IP, it is often not necessary to do any pre-join configuration (this is not the case with SmartMesh WirelessHART). As an example however, assume your microcontroller sets the mote's network ID. The

SmartMesh C Library

 command is dn_ipmt_setParameter_networkId(). It takes 2 arguments: a 16-bit network ID, and a pointer to a buffer that will contain the reply (a struct) from the mote. 

The examples set a 500 ms serial response timeout for the mote to respond - this is very conservative, as commands are expected to be answered within 125 ms. Either a reply arrives, cancelling the timer and scheduling the next event, or it times out and the FSM returns to the starting state - getting mote status.

At the lower levels, each API call results in a command buffer being constructed and passed to dn_serial_mt_sendRequest(), which in turn calls a series of dn_hdlc_outputOpen/Write/Close functions, which ultimately call your dn_uart_txByte() function. dn_hdlc_outputClose also calls dn_uart_txFlush() in case you have a buffer oriented UART, in which case your dn_uart_txByte() accumulates bytes into a transmit buffer until it is flushed.

  • Issue join command
  • The dn_ipmt_join() command takes a reply buffer as an argument.  The example FSM logic is as above - wait for a reply, which either arrives and the FSM moves to the next state, or it times out and the FSM restarts.  Your application could do something different, e.g. retry the join command a few times, then reset the mote if it seems unresponsive.  The time between states is set to 1s (CMD_PERIOD). It could be faster or slower - the tradeoff is between responsiveness and power.  It can take 10's of seconds under good conditions between the join command and the mote becoming operational, so polling every 1s is less efficient, but since joining is an infrequent activity, it doesn't matter in the long term.  

  • Monitor join progress

For your application to be able to send data, the mote must be in the OPERATIONAL state. Once in the operational state, by default each mote in a SmartMesh IP network has enough bandwidth to publish a data packet every 9 seconds.  In a single vendor vertically integrated system, it may be safe to just send at this rate, since you know that all devices will be respecting the 9 s limit.  If motes need more bandwidth, or there may be devices from different vendors, or there is the possibility that the manager may be running a custom configuration, then it is recommended that your application requests a service using dn_ipmt_requestService(). Services are always required for SmartMesh WIrelessHART motes.

The mote's reply only means that the command was accepted. When the manager has finished laying in the bandwidth to support the service, the mote generates a service changed event - see the Serial API guide for the relevant event bitmask.  Your application can also periodically issue the dn_ipmt_getServiceInfo() command to check on the service value. 

  • Publish data

In order to publish data on a SmartMesh IP mote, you first need to open and bind a socket to a particular UDP port.  Port selection is completely up to you. The ports 0xf0b8 0xf0bf are specifically set aside for your application - they offer the advantage of supporting the largest payload (90 bytes).  If you choose an arbitrary port, the payload size is reduced by 2 bytes. The manager can receive on any port, but for the mote to receive data, it must be listening to the port that the manager has specified in its sendData() command.  You can open multiple sockets, and bind a different port to each socket.

    • Call dn_ipmt_openSocket() to open a communication socket - this will give you a socketID for the socket. Currently only UDP sockets are supported.
    • Call dn_ipmt_bindSocket() to bind the socket to a port, the destPort you will use in the sendTo command.
    • Use dn_ipmt_sendTo() to send data to a specified IPv6 address - your application can use the Manager's well-known address if you don't have a specific destination.  Repeated calls to dn_ipmt_sendTo() can be made on the open socket - there is no need to close the socket unless you are completely done using it.  The sendTo command in the Serial API Guide has a description of the required fields.

In SmartMesh WirelessHART, data is always sent to the Gateway (address = 0xF981) . There are various HART Common Practice commands for configuring what data is burst, and under what circumstances - implementing burst command logic is left to the user.

  • Receive notifications

Whenever a notification is received, the notification callback will be invoked as described in "Acknowledge the mote boot event" above.  There are several types of notifications that you may want to be able to handle in your application:

    • Receive notifications occur when the manager sends data (in IP, to a bound port).  The notification contains the data and its source (in IP, an IPv6 address).
    • txDone notifications let your application know when a packet has been sent - this allows you to buffer data in the event that the mote should reset. Once the txDone notification is received, the data is delivered with 99.999% reliability.
    • Event notifications - if a boot event is received, your microcontroller should return to the pre-join configuration state. If the mote loses connection with the network or fails to join, it will generate specific events. These may be captured for display, or ignored - eventually the mote will reset and generate a boot event.

Flow Control Example

  • Install an ISR handler for an interrupt-capable GPIO on your microcontroller - when UART_TX_RTSn is asserted, the ISR sets the GPIO connected to UART_TX_CTSn.  This will allow the mote to begin sending data. You may be able to check if the microcontroller is busy in transmit, and delay UART_TX_CTSn until it is done.
  • If this is a response, you can de-assert UART_TX_CTSn in your reply callback. If this is a notification, you can de-assert it in your notification callback.