10.7. Non-IP Data Delivery
10.7.1. General description
Using Non-IP Data Delivery (NIDD) feature allows for efficient communication between IoT devices and a LwM2M server. The communication is performed through the cellular network that ensures security while reducing transmission overhead required by a classic network stack (IP, TCP and UDP protocols), still allowing to send up to 1500 bytes in a single transmission. Utilizing an IP protocol stack for data delivery is considered to be a power hungry process. By using Non-IP Data Delivery instead, the device can reduce its power consumption.
Non-IP Data Delivery feature provides easy support for different modem devices by allowing the user to define device wrappers that will be used to communicate with the hardware. Anjay comes with one implementation of such device wrapper for the Quectel BG96 modem.
10.7.2. Technical documentation
10.7.2.1. Enabling NIDD support
If Non-IP Data Delivery support is available in your version of Anjay, it can be enabled at
compile time by enabling the ANJAY_WITH_NIDD
macro in the anjay_config.h
file or, if using CMake, enabling the corresponding WITH_NIDD
CMake option.
Note
The example in this documentation uses the BG96 wrapper for the NIDD driver
that must be enabled at compile time by setting the ANJAY_WITH_MODULE_BG96_NIDD
macro in the anjay_config.h
file or by using WITH_MODULE_bg96_nidd
CMake option.
10.7.2.2. Usage example
Note
The full code for the following example can be found in the
examples/commercial-features/CF-NIDD
directory in Anjay sources. Note
that to compile and run it, you need to have access to a commercial version
of Anjay that includes the Non-IP Data Delivery feature.
In this example we will use a BG96 wrapper for an NIDD driver that is part of Anjay. To run this example on a Linux-based system you will need to have a Quectel BG96 modem connected to your PC or utilize the Python script found in tests/integration/framework/nidd/modem.py that will simulate BG96 modem and act as a proxy to connect to a LwM2M server.
Note
The Python modem.py script creates a pseudo-terminal device which acts like an AT modem. NIDD network requests generated by Anjay are sent over UDP socket.
Note
To set up the proxy with the Python script run ./modem.py --host HOST_IP_ADDRESS --port PORT_NUMBER
command before launching the example. After starting the script it will display
the path of the device that simulates the a BG96 modem.
Firstly we will introduce a helper function that will open the device associated with the modem proxy and create an NIDD driver for communication.
anjay_nidd_driver_t **demo_nidd_driver_create(const char *modem_device) {
demo_nidd_driver_t *driver =
(demo_nidd_driver_t *) avs_calloc(1, sizeof(*driver));
if (!driver) {
return NULL;
}
const anjay_bg96_nidd_config_t config = {
.system_descriptor = &driver->pts_fd,
.user_context = driver,
.modem_getline = modem_getline,
.modem_write = modem_write,
.modem_get_parameter = modem_get_parameter
};
if (fifo_init(&driver->fifo)) {
avs_log(tutorial, ERROR, "could not initialize FIFO");
goto fail;
}
if ((driver->pts_fd = open(modem_device, O_RDWR)) < 0) {
avs_log(tutorial, ERROR, "could not open modem device %s: %s",
modem_device, strerror(errno));
goto fail;
}
if (!(driver->bg96_nidd = anjay_bg96_nidd_driver_create(&config))) {
avs_log(tutorial, ERROR, "could not create AT NIDD driver");
goto fail;
}
return &driver->bg96_nidd;
fail:
driver_cleanup(driver);
return NULL;
}
Important
If the user does not use the BG96 driver delivered with Anjay, a set of functions has to be to implemented that will allow communication with the modem device. More information about the needed functions can be found here:
This function calls anjay_bg96_nidd_driver_create(...)
function that fills
anjay_nidd_driver_t
structure with callback functions used to integrate with
BG96 modem. The structure with the callback functions containing implementation
of modem integration layer is returned on success. We call this function before
filling anjay_configuration_t
structure and passing the returned pointer to
.nidd_driver
.
int main(int argc, char *argv[]) {
if (argc != 3) {
avs_log(tutorial, ERROR, "usage: %s ENDPOINT_NAME MODEM_PATH", argv[0]);
return -1;
}
anjay_nidd_driver_t **demo_nidd_driver = demo_nidd_driver_create(argv[2]);
if (!demo_nidd_driver) {
avs_log(tutorial, ERROR, "Could not create NIDD driver");
return -1;
}
const anjay_configuration_t CONFIG = {
.endpoint_name = argv[1],
.in_buffer_size = 4000,
.out_buffer_size = 4000,
.msg_cache_size = 4000,
.nidd_driver = *demo_nidd_driver
};
anjay_t *anjay = anjay_new(&CONFIG);
if (!anjay) {
avs_log(tutorial, ERROR, "Could not create Anjay object");
return -1;
}
int result = 0;
// Setup necessary objects
if (setup_security_object(anjay) || setup_server_object(anjay)) {
result = -1;
}
if (!result) {
result = anjay_event_loop_run(
anjay, avs_time_duration_from_scalar(1, AVS_TIME_S));
}
anjay_delete(anjay);
demo_nidd_driver_cleanup(demo_nidd_driver);
return result;
}
Important
If nidd_driver
is not NULL
, it will enable NIDD transport.
If Anjay configuration used does not support Non-IP Data Delivery feature, setting this to
a non-NULL will cause an error.
Before calling anjay_event_loop_run
we need to set up Security and Server objects.
static int setup_security_object(anjay_t *anjay) {
if (anjay_security_object_install(anjay)) {
return -1;
}
const anjay_security_instance_t security_instance = {
.ssid = 1,
.server_uri = "coap+nidd://",
.security_mode = ANJAY_SECURITY_NOSEC
};
// Anjay will assign Instance ID automatically
anjay_iid_t security_instance_id = ANJAY_ID_INVALID;
if (anjay_security_object_add_instance(anjay, &security_instance,
&security_instance_id)) {
return -1;
}
return 0;
}
// Installs Server Object and adds and instance of it.
// An instance of Server Object provides the data related to a LwM2M Server.
static int setup_server_object(anjay_t *anjay) {
if (anjay_server_object_install(anjay)) {
return -1;
}
const anjay_server_instance_t server_instance = {
// Server Short ID
.ssid = 1,
// Client will send Update message often than every 60 seconds
.lifetime = 60,
// Disable Default Minimum Period resource
.default_min_period = -1,
// Disable Default Maximum Period resource
.default_max_period = -1,
// Disable Disable Timeout resource
.disable_timeout = -1,
// Sets preferred transport to NIDD
.binding = "N"
};
// Anjay will assign Instance ID automatically
anjay_iid_t server_instance_id = ANJAY_ID_INVALID;
if (anjay_server_object_add_instance(anjay, &server_instance,
&server_instance_id)) {
return -1;
}
return 0;
}
Server URI should be set to coap+nidd://
, security mode should be ANJAY_SECURITY_NOSEC
and binding in server object should be set to ‘N’.