Enabling IoT Devices for SkyCase

SkyCase is a designed and provided as an open-source community enabled platform with open support for creating SkyCase applications as well as the devices. Since the SkyCase internally uses the LWM2M object model, which itself is designed specifically for M2M/IoT devices, it is easier if the device adheres to the same. Though it is possible to use device specific broker interface where by a custom data transport can be mapped to the internal object model, it is recommended to use the LWM2M model to leverage existing features and wider adaptation.
This document describes the steps involved in downloading the source, compiling it and creating IoT devices with the same.

LWM2M/SkyCase Client Library

The source code for the SkyCase client is available on GitHub at https://github.com/embien/lwm2m_client. Technically it is a LWM2M client implementation that provides two kinds of underlying transport:
CoAP/UDP mode: When this mode of communication is enabled, the library acts as LWM2M client which can be used to communicate with any LWM2M servers like Embien's LWM2M Server available from Google Play store.
REST/TCP mode: In this mode of transport, the library can be used to communicate with the SkyCase server. The procedure for the same is explained in the below section. User can also find more help information under directory path lwm2m_client/doc.

Being an ANSI-C library, the code can be used in any platform as long as it has an Internet connection. It could be used over an OS or even without any in a single while loop model. Also since it is written considering resource constrained environments, the code can be run on top of a small microcontroller with even 2G GSM connectivity. Different platforms that can be enabled to communicate with SkyCase includes Raspberry-PI, Arduino, FRDM platforms, mbed platforms, PCs etc.

In this case, we will consider the running the code in a Windows PC making it a LWM2M client. Compilation of source code requires Visual Studio 2008 or above. And, as can be considered as a simulator. this will be a good case for testing the connectivity logic of the device implementation.

Enabling IoT Devices for SkyCase

This section takes implementation of a simple device that has 2 digital inputs and 1 digital output as the example. This could be the basis for creating a more powerful IoT device, like a Smart Home controller, that can have a number of ports each for controlling different aspects of a home.

Downloading the source

Download the source code for the SkyCase client from GitHub repository. Open the VS2008 project available under bin/Win32 directory of the source.

Configuring the device

User can edit the configuration of the device from the file "lwm2m_client/app/lwm2m_config.h".

Setting up Communication Mode Setup (LWM2M_CLIENT_COMM_MODE):

As explained earlier, there are two types of client communication modes available.

LWM2M_CLIENT_COMM_UDP_COAP - For LWM2M client mode to work on UDP/CoAP.
LWM2M_CLIENT_COMM_HTTP_SKYCASE - SkyCase Platform client for with TCP/REST transport.

In our case, the mode must be set to SkyCase as follows:
#define LWM2M_CLIENT_COMM_MODE LWM2M_CLIENT_COMM_HTTP_SKYCASE
Setting up User Access (SC_CLIENT_USER_NAME)

As every device that communicates with SkyCase must be authenticated under a user credential, the above MACRO must be configured suitably. The value of this MACRO is a combination of user mode and user name in the format

<OEM Code>:<Product Code>
When using as a standalone developer, use a value of 0 for OEM code and your username for product code. For example use "0:demo_user", in case your username as registered with SkyCase is demo_user.
#define SC_CLIENT_USER_NAME "0:demo_user"
Please make sure the value is given as a string as shown above.

Client Object Model

The LWM2M client implements all IPSO/LWM2M standard objects and its handlers defined so far. Modular client design leads to easy implementation of new objects and it's communication with SkyCase. For use with embedded systems, dynamical memory allocation is not used and objects and their access methodology are done using predefined structures and definitions.

SkyCase client library is provided with few default applications including a full fledged demo. But creating a new application is an easy task. The designers need to do the following:

1. Enable and configure the lwm2m objects in his header file. User's header file should specify the configurations as explained in the following lines.
2. Specify the maximum supported objects by setting the macro
LWM2M_MAX_SUPPORTED_OBJECTS
3. Enable supported objects by enabling the respective MACRO named as
LWM2M_OBJ_SUPPORT_<object name>
4. Specify the number of maximum supported resources in the each enabled objects with
LWM2M_USER_DEV_<object>_RES_MAX
5. Set the maximum number of instances in the each enabled objects using
LW_MAX_INST_<object>
6. Create instances of structure LWM2M_OBJECT_RES_INFO for each of the object devices named
user_dev_<object>_res_info [LWM2M_USER_DEV_<object>_RES_MAX]
7. Providing a call back function for each of the resources in the form given below in these structures and implement the same which will be called when any of these resources are written or read by the SkyCase/LWM2M server.
int resource_handler (INT16S u16_inst_id, INT8U u8_oper, void *ptr_value);

Client Application Logic

Now that the object model of the device are defined, the client application must implement the logic in the following method

1. Perform a onetime initialization process to perform operating s like resource allocation etc.
2. Either continuously in between your core logic or or on demand, once any data is ready to be sent to the SkyCase server, transmit the same.
3. Also check the piggy-backed response from the server which might have some requests originating in the device side or periodically poll for any requests. Once any request is pending, execute the same and clear those requests.

Demos Provided

The SkyCase library is provided with following demos by default:
Full Demo - A command line app with menu based input to perform all possible operations on the SkyCase server
XOR Demo - A counterpart to example explained in Basic App Development that has a test device with 2 inputs changing in random and one output driven by cloud

Either of these can be enabled by setting the following configuration option suitably LWM2M_CLIENT_MAIN_APP

XOR Demo Execution and Implementation

Now to run the XOR Demo, set

#define LWM2M_CLIENT_COMM_MODE LWM2M_CLIENT_COMM_HTTP_SKYCASE
#define SC_CLIENT_USER_NAME "0:demo_user" //Must be your user name
#define LWM2M_CLIENT_MAIN_APP LWM2M_CLIENT_MAIN_APP_XOR_DEMO
Compiling the code(using the Visual Studio project in bin/win32 directory) and executing the code will automatically connect the device to SkyCase server. Register the same as explained in Registering IoT Devices with SkyCase section.
Now install the DigitalXOR application as explained in Managing IoT devices with SkyCase Apps section. You can see from the prints that the inputs are changing in random and the output is driver from cloud as XOR'ed value of the inputs.

Implementation of the XOR Client Demo is explained below.

By setting LWM2M_CLIENT_MAIN_APP as LWM2M_CLIENT_MAIN_APP_XOR_DEMO, the following files
xor_demo/process_xor_demo.h
xor_demo/process_xor_demo.c
are included in the project and object/resource call back provided in it are used.

Here the object model is defined as below to simulate 2 inputs and 1 output.
#define LWM2M_MAX_SUPPORTED_OBJECTS 2 /*!< LWM2M maximum supported object list */
#define LWM2M_OBJ_SUPPORT_IPSO_DIG_IN 1 /*!< LWM2M client enable or disable the IPSO digital input objects */
#define LWM2M_OBJ_SUPPORT_IPSO_DIG_OUT 1 /*!< LWM2M client enable or disable the IPSO digital */
#define LWM2M_USER_DEV_DIG_IN_RES_MAX 1
#define LWM2M_USER_DEV_DIG_OUT_RES_MAX 1
#define LW_MAX_INST_IPSO_DIG_IN 2 /*!< LWM2M maximum instance list for IPSO digital input object */
#define LW_MAX_INST_IPSO_DIG_OUT 1 /*!< LWM2M maximum instance list for IPSO digital */
extern LWM2M_OBJECT_RES_INFO user_dev_dig_in_res_info [LWM2M_USER_DEV_DIG_IN_RES_MAX];
extern LWM2M_OBJECT_RES_INFO user_dev_dig_out_res_info [LWM2M_USER_DEV_DIG_OUT_RES_MAX];
The main logic is implemented using simple state machines. Each request to SkyCase is handled synchronously and it must be completed before starting the next one.
To save memory, all the possible request and response structures are combined together in an union named XOR_PACKET_INFO
typedef union __xor_packet_info
{
SC_PKT_COMMON_RESP_INFO info_common_resp;
SC_PKT_DEV_REG_RESP_INFO info_dev_reg_resp;
SC_PKT_DATA_WRITE_REQ info_data_write_req;
SC_PKT_DATA_WRITE_RESP info_data_write_resp;
SC_PKT_DATA_READ_REQ info_data_read_req;
SC_PKT_DATA_READ_RESP info_data_read_resp;
SC_PKT_READ_PENDING_REQ_RESP info_pending_req_resp;
SC_PKT_DEL_PENDING_REQUESTS_REQ info_del_req_req;
SC_PKT_DEL_PENDING_REQUESTS_RESP info_del_req_resp;
} XOR_PACKET_INFO;
Functions like 'sc_set_resp_pkt_info', 'sc_set_command' and 'sc_get_last_cmd_result' are used to perform the REST request/responses.More documentation of the same are provided with the code.

The XOR Demo implements the state machine steps

1. Device Registration - Register the all enabled objects with the SkyCase.
sc_set_resp_pkt_info (ptr_dev_reg_resp, sizeof(SC_PKT_DEV_REG_RESP_INFO));
sc_set_command (SC_CMD_DEVICE_REGISTER, NULL);
2. Reading Pending Requests - Reading the pending requests from SkyCase.
sc_set_resp_pkt_info (ptr_pending_req_read_resp_info, sizeof(SC_PKT_READ_PENDING_REQ_RESP));
sc_set_command (SC_CMD_READ_PENDING_REQUESTS, NULL);
3. Data Update on SkyCase - If any data read request is received.
sc_set_resp_pkt_info (ptr_data_write_resp_info, sizeof(SC_PKT_DATA_WRITE_RESP));
sc_req_add_data_write (ptr_data_write_req_info, 3200, 0, 5500);
sc_req_add_data_write (ptr_data_write_req_info, 3200, 1, 5500);
sc_set_command (SC_CMD_DATA_WRITE, ptr_data_write_req_info);
4. Write On Device - If any data write request is received.
LWM2M_PROCESS_INFO ptr_proc_req;
ptr_proc_req.object_path [LWM2M_PATH_INDEX_OBJECT] = ptr_pending_req_read_resp_info->req_info [index].u16_obj_id;
ptr_proc_req.object_path [LWM2M_PATH_INDEX_INST] = ptr_pending_req_read_resp_info->req_info [index].u16_inst_id;
ptr_proc_req.object_path [LWM2M_PATH_INDEX_RES] = ptr_pending_req_read_resp_info->req_info [index].u16_res_id;
strcpy (ptr_proc_req.value, &ptr_pending_req_read_resp_info->req_info [index].u8_value);
lwm2m_process_request_obj (&ptr_proc_req);
5. Delete processed Requests
sc_req_add_del_pending_req (ptr_del_pending_req_info,\
ptr_pending_req_read_resp_info->req_info [index].u32_req_id, 0);
sc_set_resp_pkt_info (ptr_del_pending_resp_info, sizeof(SC_PKT_DEL_PENDING_REQUESTS_RESP));
sc_set_command (SC_CMD_DEL_PENDING_REQUESTS, ptr_del_pending_req_info);
6. Repeat from Step 2.

With this implementation, the XOR demo works to perform a simple task demonstrating IoT device management from SkyCase server.