Implementation Guidelines
Please note the following points when implementing things with the Thing-IF SDK.
Tasks
When implementing with the Thing-IF SDK, you will need to handle multiple tasks (threads).
For example, you will implement some callback functions in your thing program. These callback functions will be executed from the dedicated tasks managed by the SDK. For some features, like the SDK initialization, the thing program will create a task and invoke the SDK.
The following table summarizes the tasks.
Process | Which task executes the process? | Description |
---|---|---|
Initializing, Onboarding |
Any task in your program | Any task in your program can execute the SDK initialization. Once the initialization is done, there is no more SDK execution the task needs to make. The task can idle or execute non-Thing Interaction Framework processes. |
Executing Action Handler | Command reception task | The SDK manages a dedicated task for receiving a command. This task will execute the action handler. |
Executing State Handler | State updating task | The task that executes the state handler depends on the upload timing:
|
Allocating Resource for Parsing JSON | Any task requesting to parse JSON (in the SDK and in your program) | The thing program can have a callback function to allocate the necessary resources for parsing JSON tokens. This callback function will be executed from the tasks that request the JSON parsing. Multiple JSON parsing requests can come simultaneously, so the callback function must be reentrant or need to be serialized with the synchronous process. |
Note these points:
In addition to the tasks in this table, the Thing SDK Embedded starts a task which periodically sends MQTT PINGREQ commands. This task prevents the MQTT connection from being disconnected when the connection is idle and does not affect processes executed outside the SDK.
All the APIs on the thing are blocking APIs. Once a task calls any API, it freezes until the API completes.
Data types
Many data types are used in the Thing-IF SDK. In the guide, we will introduce them as they appear in the sample code. Here, we present a commonly-used one (kii_bool_t).
kii_bool_t
The following kii_bool_t
is the boolean data type commonly used throughout the SDK.
typedef enum kii_bool_t {
KII_FALSE = 0,
KII_TRUE
} kii_bool_t;
This data type will be imported automatically when you include kii_thing_if.h. The actual declaration is made in kii_core.h that kii_thing_if.h uses internally.
Please be careful not to confuse the APIs that return this boolean type with the ones that return error codes. Most APIs return kii_bool_t
, but some APIs return error codes. If your code skips comparing the returned value, it might become hard to comprehend at a glance. Please check the following example:
/* Initialize the Thing-IF SDK. */
if (init_kii_thing_if(...)) {
/* The function succeeded and returned kii_bool_t. */
}
/* Parse a JSON string. */
if (kii_json_read_object(...)) {
/* The function failed and returned kii_json_parse_result_t. */
}
String handling
All strings handled by the Thing-IF SDK's C library are null-terminated UTF-8 strings unless described otherwise.
You should have no problem handling characters in the ASCII range. Should you need to use the characters outside the ASCII range (e.g., in the command parameters), you need to handle them as the UTF-8's multibyte characters.
Memory management
The Thing-IF SDK receives designated memory spaces for particular uses from the user program. Heap memory is not used other than these memory spaces.
Process with designated spaces
The SDK gets designated memory spaces for the following purposes at initialization. The user program reserves these memory spaces with the initialization API during SDK initialization.
- Space for the command handler
- Space for receiving MQTT messages
- Space for updating the state
See the sample code of initialization for how to allocate the memory spaces.
General API process
Be careful with the life cycle of memory spaces for APIs which do not use designated spaces. The SDK does not use heap memory for those APIs. Therefore, specified memory spaces as arguments need to be retained for the period in which API results are used.
See the below pseudo code of a program which uses the Thing-IF SDK. An implementation like this would point to non-existent memory space and could cause unexpected behaviors in subsequent processes.
kii_bool_t myInitialize(kii_thing_if_t* kii_thing_if, ...) {
/* Assume that the lengths of the AppID, AppKey and site have been checked. */
char appID[100], charAppKey[100], site[10];
strcpy(appID, config_getAppID());
strcpy(charAppKey, config_getAppKey());
strcpy(site, config_getSite());
/* The program might crash when the SDK uses kii_thing_if */
return init_kii_thing_if_with_onboarded_thing(kii_thing_if, appID, appKey, site, ...);
}
The above example specifies the AppID and the site for an application as arguments of the init_kii_thing_if_with_onboarded_thing
to initialize the kii_thing_if
structure. The caller of the myInitialize
will use the initialized kii_thing_if
.
On the other hand, the API internally implements the below code.
typedef struct kii_thing_if_t {
char* appID;
char* appKey;
char* site;
} kii_thing_if_t;
kii_bool_t init_kii_thing_if_with_onboarded_thing(kii_thing_if* thingIf, char* appID, char* appKey, char* site, ...) {
thingIf->appID = appID;
thingIf->appKey = appKey;
thingIf->site = site;
return KII_TRUE;
}
The myInitialize
calls the API by reserving string buffers on the stack. API does not internally copy the values to heap memory but initialize the kii_thing_if
by using the pointers to the spaces of the caller without change. The buffer on the stack will be discarded when the myInitialize
process is complete. Therefore, the kii_thing_if
will have an invalid reference. This will cause a defect which is very difficult to find.
Such a problem can occur in not only the initialization API but all the Thing-IF APIs. Retain the memory spaces which the API receives from the caller while the API result is used.
Macros for build settings
The Thing-IF SDK provides some rooms for customizing the build conditions with macros. Usually, you do not need to touch these macros. When you need some deep customization and need to dig into the SDK's source code, please use the following information as your reference.
The following table summarizes the available macros. The "default" column in the table shows the default value set in the reference implementation.
Symbol | Module using this symbol | Default | Description |
---|---|---|---|
DEBUG | KiiThingSDK-Embedded | Undefined | Set this macro if you want to log debug information. The debug information includes the execution position with the source file name and line number and requests and responses of the REST API. The destination of the logged information is the logger_cb_impl function in the reference implementation. |
KII_JSON_FIXED_ TOKEN_NUM |
kii_json, KiiThingSDK-Embedded, thing-if-ThingSDK | 128 | The size of the buffer (i.e., the number of token) to allocate for parsing JSON. Please read here for the details. Consider increasing the value if the action parameter is complex. This macro is mutually exclusive with FLEXIBLE_JSON_TOKEN. |
FLEXIBLE_JSON_ TOKEN |
kii_json, KiiThingSDK-Embedded, thing-if-ThingSDK | Undefined | Define this macro to parse JSON strings with dynamically allocated memory. If this macro is defined, kii_json calls a callback function specified with kii_json_t.resource_cb when memory is required. When the callback function allocates memory, kii_json uses it to parse JSON strings. See the comments for resource_cb for the implementation method. This macro is mutually exclusive with KII_JSON_FIXED_TOKEN_NUM. |
KII_PUSH_KEEP_ALIVE_ INTERVAL_SECONDS |
KiiThingSDK-Embedded, thing-if-ThingSDK | 300 | Set the number of seconds for the MQTT keep alive timer. This is used as the value of the keep alive timer specified with the CONNECT command and as the interval of sending the PINGREQ command from the client. Kii recommends to set a value which is greater than or equal to 60. |
KII_SOCKET_MAX_ BUFF_SIZE |
KiiThingSDK-Embedded | Undefined | The size of buffer (in bytes) to allocate for the socket communication. All HTTP messages will be chunked in this size. The SDK will apply the optimal value (256 bytes) if the symbol is undefined. |
KII_THING_IF_NOASSERT | thing-if SDK | Undefined | Define this macro if the system library does not support assert . The reference implementation will automatically define the macro according to the running environment, so you can leave it undefined. |
KII_JSON_NOASSERT | kii_json | Undefined | Define this macro if the system library does not support assert . The reference implementation will automatically define the macro according to the running environment, so you can leave it undefined. |
JSMN_PARENT_LINKS | kii_json, KiiThingSDK-Embedded | Undefined | The setting for the library the SDK internally uses for parsing JSON. Please leave it undefined. |
JSMN_STRICT | kii_json, KiiThingSDK-Embedded | Undefined | The setting for the library the SDK internally uses for parsing JSON. Please leave it undefined. |
KII_USE_CUSTOM_ HTTP_CLIENT |
KiiThingSDK-Embedded | Undefined | For the future expansion (aimed to be used for replacing the HTTP/HTTPS client implementation). Please leave it undefined. |