5.4.3. Multi-instance read-only object with fixed number of instances
Note
This section describes in details the implementation of custom Objects in Anjay, either defined in OMA LwM2M Object and Resource Registry or designed by user.
Although most of the Object’s code can be generated using Anjay Object stub generator if you have Object’s definition in XML, it is recommended to read this section to have a clear understanding on what various parts of the LwM2M Object code are for.
In this example you will learn how to implement list_instances
handler for a
multi-instance LwM2M Object.
The implemented Object will look as in Single-instance read-only object, but will now support multiple Object Instances:
Name |
Object ID |
Instances |
---|---|---|
Test object |
1234 |
Multiple |
Each Object Instance has two Resources:
Name |
Resource ID |
Operations |
Instances |
Mandatory |
Type |
---|---|---|---|---|---|
Label |
0 |
Read |
Single |
Mandatory |
String |
Value |
1 |
Read |
Single |
Mandatory |
Integer |
Note
The code is based on Single-instance read-only object.
First of all, let us define a structure that will hold both handlers and object state, initialize and register it:
typedef struct test_instance {
const char *label;
int32_t value;
} test_instance_t;
typedef struct test_object {
// handlers
const anjay_dm_object_def_t *obj_def;
// object state
test_instance_t instances[2];
} test_object_t;
// ...
// initialize and register the test object
const test_object_t test_object = {
.obj_def = &OBJECT_DEF,
.instances = { { "First", 1 }, { "Second", 2 } }
};
anjay_register_object(anjay, &test_object.obj_def);
Now, to inform the library the Object contains two Instances with IDs 0 and 1, one additional handler is required:
list_instances
- used by the library to enumerate all existing Object Instance IDs:static int test_list_instances(anjay_t *anjay, const anjay_dm_object_def_t *const *obj_ptr, anjay_dm_list_ctx_t *ctx) { (void) anjay; // unused test_object_t *test = get_test_object(obj_ptr); for (anjay_iid_t iid = 0; (size_t) iid < sizeof(test->instances) / sizeof(test->instances[0]); ++iid) { anjay_dm_emit(ctx, iid); } return 0; }
Note that the instances MUST be returned in a strictly ascending, sorted order.
Having done that, resource_read
handler needs to be slightly modified
to correctly handle requests to different Object Instance IDs.
static int test_resource_read(anjay_t *anjay,
const anjay_dm_object_def_t *const *obj_ptr,
anjay_iid_t iid,
anjay_rid_t rid,
anjay_riid_t riid,
anjay_output_ctx_t *ctx) {
(void) anjay; // unused
test_object_t *test = get_test_object(obj_ptr);
// IID validity was checked by the `anjay_dm_list_instances_t` handler.
// If the Object Instance set does not change, or can only be modified
// via LwM2M Create/Delete requests, it is safe to assume IID is correct.
assert((size_t) iid < sizeof(test->instances) / sizeof(test->instances[0]));
const struct test_instance *current_instance = &test->instances[iid];
// We have no Multiple-Instance Resources, so it is safe to assume
// that RIID is never set.
assert(riid == ANJAY_ID_INVALID);
switch (rid) {
case 0:
return anjay_ret_string(ctx, current_instance->label);
case 1:
return anjay_ret_i32(ctx, current_instance->value);
default:
// control will never reach this part due to test_list_resources
return ANJAY_ERR_INTERNAL;
}
}
The only thing left to do is plugging created handler into the Object Definition struct:
static const anjay_dm_object_def_t OBJECT_DEF = {
// Object ID
.oid = 1234,
.handlers = {
.list_instances = test_list_instances,
// ... other handlers
}
};
Note
Complete code of this example can be found in examples/tutorial/AT-CustomObjects/read-only-multiple-fixed subdirectory of main Anjay project repository.