nRF5 IoT SDK
v0.9.0
|
Nordic's LWM2M library supports the LWM2M Client role.
The LWM2M library included in the SDK improves the memory footprint by using statically assigned object instances to handle requests to an object. There is a separate callback for requests going to the root object.
The Figure 1 below demonstrates how the IPSO digital output object is configured using the lwm2m_object_prototype_t, in order to act as an object handler for this object type.
The library structures the CoAP resources differently from that of Nordic's CoAP library (see Nordic's CoAP) in order to improve the memory RAM footprint. The difference in the two structures lies in defining a common callback for all object instances of an object rather than one dedicated callback for each resource. Depending on the URI path for the object instance provided in the callback on request notification, the application is able to distinguish whether the request is for the instance or a specific resource.
Each LWM2M object instance definition consists of :
In order to maintain resource definitions and access permissions in an object, additional information called operations and resources_ids is included in each object. These fields are indices to lists that maintain the information for all the objects and their data members.
Figure 2 demonstrates how an IPSO digital output object instance is configured to act as an object instance handler.
In order to disable a data member from the struct, a NONE permission could be entered in the operations list of that object. This will disable the resource from being accessed. The CoAP request matching will also be disabled for this resource if attempted to be accessed, and the instance callback will not be called. On the other hand, a CoAP error code "Not Found" will be returned by the LWM2M CoAP middleware automatically.
Each request will be forwarded to the appropriate handler based on the URI defined in the CoAP request. The instance or resource that exist in the system determines what callback LWM2M will choose. Below there is a diagram showing how different scenarios are mapped to the two prototype forms which exist in the system.
The first image shows a DELETE request to a root object. This is forwarded to the callback of the registered object. Second there is a DELETE request to a specific instance in the system. This cannot be handled by the instance handler itself and needs to be handled by the object handler. The instance id used to manipulate is passed as a parameter to the object callback function. As shown in the third diagram, a PUT request is done as an instance URI. This is forwarded to the instance handler which has that instance id. Forth, there is a PUT request on a resource contained in the object instance. This is forwarded to the instance handler and provides the resource id of the resource to be manipulated.
This API shall be called before using any other APIs of the module. If this API fails, none of the module APIs shall be used by the application. Prior to calling the LWM2M initialization function, coap needs to be initialized, along with its port configuration. This is described in Initialization.
Example demonstrating how to initialize the LWM2M module.
Notifications from LWM2M could come asyncronously from the LWM2M module. The notification type will indicate the source of the notification event. For example an event could come if registration has been issued and the server is acknowleding the request.
The example below demonstrates how to catch a notification from the register interface.
Since the library does not provide any object or entry for the root, any requests to the "/" object will be propagated to the lwm2m_coap_handler_root
API function. For example, this could be called during Bootstrap, when the bootstrap server issues a delete request on the root. As no object or instance has been registered to handle this, a callback to this function is done, providing the original CoAP request and the parsed LWM2M operation code. The application will have to do an appropriate action upon such request.
The example below shows an implemented handler that only responds to a DELETE operation request without doing any further action.
Any object which will be registered in the library to handle LWM2M requests has to be initialized. The base of any object is a lwm2m_object_prototype_t structure. Since there is only one object for a given object ID in the system at a time, there is no need to run an additional initialization function (like for instances) other than populating the structure.
The lwm2m_object_prototype_t has two fields that need to be populated. One is the Object Identfier and the second is the callback function which is called upon to send a request message to the object.
A set of OMA LWM2M object identifier definitions can be found in OMA LWM2M objects definititions and types. For IPSO Smart Objects, a set of object identifier definitions can be found in IPSO Smart Object definititions and types.
The code below demonstrates how a security object instance could be populated to act as the parent of all the instances with a corresponding Object ID.
Any object instance registered in the library to handle LWM2M requests has to be initialized.
The base of any object is a lwm2m_instance_prototype_t structure which is referred to as the proto field in each object structure definition. A set of OMA LWM2M object definition structures can be found in OMA LWM2M objects definititions and types. For IPSO Smart Objects, a set of object definition structures can be found in IPSO Smart Object definititions and types. The proto fields have to be populated after the strucuture has been initialized. This is done by passing the pointer to the object type structure into a corresponding init function for the object type.
A set of OMA LWM2M object initialization functions for the object structures can be found in OMA LWM2M objects definititions and types. For IPSO Smart Objects, a set of initialization functions for the object structures can be found in IPSO Smart Object definititions and types.
After initializing the structure, the proto member of the structure has 3 fields that needs to be populated. The first is the Object Identifier which connects the instance to a parent object, the second is the Instance Identfier which is the instance number in the application, and the third is the callback function which is called upon the request message to the object.
The code below demonstrates how an object instance can be initilized and populated.
The library assumes that the resources use an object identifier, instance identifier, and resource identifier of uint16_t
type. In some special cases it is necessary to create objects with a different identifier. For this case a special object type can be defined. If the object's object_id field is set to to LWM2M_NAMED_OBJECT it will be handled as a Named Object. The alias name has to be provided which is done by setting the p_alias_name field of the object.
If registered using the lwm2m_coap_handler_object_add any request to the object will be resolved. However, the named objects will be rendered as part of the device when generating the Link Format string using the lwm2m_coap_handler_gen_link_format.
The example below demonstrates how an object named "bs" can be created in order to handle a request to a CoAP request with URI-path "/bs".
Enabling an object to handle requests requires that it is added to the CoAP handler in the library by calling the lwm2m_coap_handler_object_add API function. This will register the object in an internal CoAP resource handler list. Upon requests, the URI paths of the request will be parsed and checked against the object list. If a match exists, the callback function defined by the matching object will be issued.
The code below demonstrates how to add an object to the library's CoAP request handler.
To disable an object from handling requests it has to be removed from the CoAP handler in the library by calling the lwm2m_coap_handler_object_delete API function.
This will deregister the object from the internal CoAP resource handler list. Once the object is removed, if a request is sent to the object, the library will respond with a 404 Not Found error.
The code below demonstrates how to delete an object from the library's CoAP request handler.
To enable an object instance to handle requests, it has be added to the CoAP handler in the library by calling the lwm2m_coap_handler_instance_add API function. This will register the object instance in an internal CoAP resource handler list. Upon requests, the URI paths of the request will be parsed and checked against the object instance list. If a match exists, the callback function defined by the matching object instance will be issued.
By adding an object instance, the library will also automatically try to match all resource IDs within the instance.
The code below demonstrates how to add an object instance and belonging resources to the library's CoAP request handler.
In order to disable an object instance from handling requests it has to be removed from the CoAP handler in the library by calling the lwm2m_coap_handler_instance_delete API function.
This will deregister the object and all associated resources from the internal CoAP resource handler list. Once the object and its resources are removed, if a request is sent to the object, the library will respond with a 404 Not Found error.
The code below demonstrates how to delete an object instance from the library's CoAP request handler.
Upon registration with a LWM2M server you must supply a Link Format string describing the objects and instances that are enabled in the client. To simplify this process, the library provides an API to traverse the objects and instances registered.
The lwm2m_coap_handler_gen_link_format takes in a buffer and a the length of the buffer. It can be dry-runned by supplying a NULL pointer as buffer and returning the length of the required memory in bytes, which is required to render the string.
The example below shows how a dry-run could be performed, followed by a memory allocation to the nrf_mem_reserve, and finally issue a call to the function again to generate the string into the provided memory.
The library provides some functions for encoding OMA LWM2M/IPSO object instances from the structure holding the resource values into a corresponding TLV format.
The encoding API functions for OMA LWM2M objects can be found in OMA LWM2M object TLV encoder and decoder API. The encoding API functions for IPSO Smart Object objects can be found in IPSO Smart Object TLV encoder and decoder API.
The encoding functions expect that the object instance has been initialized as described in Instance initialization.
Below there is an example that demonstrates encoding of an IPSO digital output Smart Object object instance into TLV encoded format.
The library provides some functions for decoding OMA LWM2M/IPSO object instances from TLV format into a corresponding structure holding the resource values.
The decoding API functions for OMA LWM2M objects can be found in OMA LWM2M object TLV encoder and decoder API. The decoding API functions for IPSO Smart Object objects can be found in IPSO Smart Object TLV encoder and decoder API.
The decoding functions expect that the object instance has been initialized as described in Instance initialization.
Below there is an example that demonstrates decoding of a security object instance in TLV format into lwm2m_security_t structure assuming a write request has been issued to the security instance.
The library provides an API function lwm2m_respond_with_payload which generates a CoAP response message based on the original request. The function takes in a payload and length of the payload in addition to the original request, and populates the CoAP message to be sent. After creating the message, it will send it to the transport layer. The CoAP message code used will always be COAP_CODE_205_CONTENT.
The example below demonstrates how to send a response message with a payload using the API.
The library provides an API function lwm2m_respond_with_code which generates a CoAP response message based on the original request adding a custom CoAP message code to it. After creating the message, it will send it to the transport layer.
The example below demonstrates how to send a response message with a custom CoAP message code using the API.
Before initating bootstrap, a named object has to be set up in order to handle the bootstrap complete event from the bootstrap server. This is not a normal LWM2M object or instance using numbers as a URI path, but a text string. This needs to be handled by registering a named object "/bs" with its belonging object callback function.
When calling the lwm2m_bootstrap API, a client initiated boostrap is triggered. Upon the acknowledgement of the registration request, a notification will be given to the application through the lwm2m_notification
callback function. The bootstrap will continue, and finish by a write to the bootstrap object.
If secure mode is enabled for the bootstrap server remote, write attempts might fail if issued during the handshake of DTLS or if the credentials where mismatching. If the write is failing, bootstrap might be re-attempted immediately, but it is recommended to wait a few seconds if the handshake is still in progress.
The example below demonstrates what would be needed to initiate a bootstrap from the client.
When calling the lwm2m_register API, a registration request to the given server is triggered. When the registration request is acknowledged, a notification is sent to the application through the lwm2m_notification
callback function.
If secure mode is enabled for the LWM2M server remote, write attempts might fail if issued during the DTLS handshake or if the credentials are mismatching. If the write is failing, bootstrap might be re-attempted immediatly, but it is recommended to wait a few seconds if handshake is still in progress.
The example below demonstrates what is needed to initiate a registration request to a given server.
If you need to update the Server configuration towards a registered server, a call to the lwm2m_update API can be issued. The function will automatically look up the "Registration ID" provided by the server during registration, and send a registration update request to the server. The lookup will be based on the remote address and port of the peer server, meaning the lwm2m_remote_t
structure has to be provided along with the server configuration for the update. The local port needs to be supplied as well to identify which local port is going to be used to transmit the registration update request. When the registration request is acknowledged, a notification will be sent to the application through the @ c lwm2m_notification callback function.
Below is an example demonstrating how a registration update request could be sent from the application.
To disconnect from a server that the application is registered with, the lwm2m_deregister API can be used. The function will automatically look up the Registration ID provided by the server during registration, and send a deregistration request to the server. The lookup will be based on the remote address and port of the peer server, meaning the lwm2m_remote_t
structure has to be provided. The local port needs to be supplied to identify which port is going to transmit the deregistration request. Upon the acknowledgement of the registration request, a notification will be given to the application through the lwm2m_notification
callback function.
Below is an example demonstrating how a deregistration request can be sent from the application.
The following configuration parameters should be defined in sdk_config.h
.
Disables debug tracing in the module. To enable tracing, this flag must be set to 0 and ENABLE_DEBUG_LOG_SUPPORT must be set to 1.
Description | Value |
---|---|
Enable debug trace | 0 |
Disable debug trace | 1 |
Dependencies | ENABLE_DEBUG_LOG_SUPPORT |
Disables API parameter checks in the module. Set this define to 1 to disable checks on API parameters in the module.
API parameter checks are added to ensure that the correct parameters are passed to the module. These checks are useful during development phase, but they might be redundant when the application is finalized. Disabling these checks might improve performance.
Description | Value |
---|---|
Enable API parameters check | 0 |
Disable API parameters check | 1 |
Dependencies | None |
Maximum number of LWM2M servers to connect to.
As boostrap server is not counted as a server in this sense; the number should reflect how many servers the device registers with.
Restriction | Value |
---|---|
Minimum value | 1 |
Maximum value | 65535 |
Dependencies | None |
Maximum number of objects supported by the device.
As objects are default resource handler for the LWM2M instances when no instance is registered, this has to be defined to set of memory for the objects that are going to be registered as handlers.
Restriction | Value |
---|---|
Minimum value | 1 |
Maximum value | 65535 |
Dependencies | None |
Maximum number of object instance supported by the device.
Maximum number of object instances. Objects are not included as an instance as the handlers are kept in a separate buffer.
Restriction | Value |
---|---|
Minimum value | 1 |
Maximum value | 65535 |
Dependencies | None |
Max number of bytes allocated for location string from remote server.
Upon registration the device will get a location string to be used as an identifier for later communication with the server it is registered to. This setting defines the maximun length of the location string a server can return upon registration with a server.
Restriction | Value |
---|---|
Minimum value | 1 |
Maximum value | 255 |
Dependencies | None |