| /** |
| * @file lwm2m_gateway.c |
| * @brief |
| * |
| * Copyright (c) 2021 Laird Connectivity |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * Gateway |
| * https://github.com/OpenMobileAlliance/lwm2m-registry/blob/prod/25.xml |
| */ |
| |
| #define LOG_MODULE_NAME net_lwm2m_gateway |
| #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(LOG_MODULE_NAME); |
| |
| #include <string.h> |
| #include <zephyr/init.h> |
| |
| #include "lwm2m_object.h" |
| #include "lwm2m_engine.h" |
| #include "lwm2m_resource_ids.h" |
| #include "lwm2m_obj_gateway.h" |
| |
| #define GATEWAY_VERSION_MAJOR 2 |
| #define GATEWAY_VERSION_MINOR 0 |
| #define GATEWAY_MAX_ID 4 |
| |
| #define MAX_INSTANCE_COUNT CONFIG_LWM2M_GATEWAY_MAX_INSTANCES |
| |
| BUILD_ASSERT(CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE >= CONFIG_LWM2M_GATEWAY_PREFIX_MAX_STR_SIZE, |
| "Gateway prefix requires validation"); |
| |
| /* |
| * Calculate resource instances as follows: |
| * start with GATEWAY_MAX_ID |
| * subtract EXEC resources (1) |
| */ |
| #define RESOURCE_INSTANCE_COUNT (GATEWAY_MAX_ID - 1) |
| |
| struct lwm2m_gw_obj { |
| char device_id[CONFIG_LWM2M_GATEWAY_DEVICE_ID_MAX_STR_SIZE]; |
| char prefix[CONFIG_LWM2M_GATEWAY_PREFIX_MAX_STR_SIZE]; |
| char iot_device_objects[CONFIG_LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_MAX_STR_SIZE]; |
| }; |
| |
| static struct lwm2m_gw_obj device_table[MAX_INSTANCE_COUNT]; |
| static struct lwm2m_engine_obj lwm2m_gw; |
| static struct lwm2m_engine_obj_field fields[] = { |
| OBJ_FIELD_DATA(LWM2M_GATEWAY_DEVICE_RID, R, STRING), |
| OBJ_FIELD_DATA(LWM2M_GATEWAY_PREFIX_RID, RW, STRING), |
| OBJ_FIELD_DATA(LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_RID, R, STRING), |
| }; |
| |
| static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT]; |
| static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][GATEWAY_MAX_ID]; |
| static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT]; |
| |
| static int prefix_validation_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, |
| uint8_t *data, uint16_t data_len, bool last_block, |
| size_t total_size) |
| { |
| int i; |
| int length; |
| bool unique = true; |
| |
| /* Prefix can't be empty because it is used to reference device */ |
| if (data_len == 0) { |
| return -EINVAL; |
| } |
| |
| /* Prefix of each gateway must be unique */ |
| for (i = 0; i < MAX_INSTANCE_COUNT; i++) { |
| length = strlen(device_table[i].prefix); |
| if (length == data_len) { |
| if (strncmp(device_table[i].prefix, data, length) == 0) { |
| if (inst[i].obj_inst_id != obj_inst_id) { |
| unique = false; |
| break; |
| } |
| } |
| } |
| } |
| |
| return unique ? 0 : -EINVAL; |
| } |
| |
| static struct lwm2m_engine_obj_inst *lwm2m_gw_create(uint16_t obj_inst_id) |
| { |
| int index, i = 0, j = 0; |
| |
| /* Check that there is no other instance with this ID */ |
| for (index = 0; index < MAX_INSTANCE_COUNT; index++) { |
| if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) { |
| LOG_ERR("Can not create instance - " |
| "already existing: %u", |
| obj_inst_id); |
| return NULL; |
| } |
| } |
| |
| for (index = 0; index < MAX_INSTANCE_COUNT; index++) { |
| if (!inst[index].obj) { |
| break; |
| } |
| } |
| |
| if (index >= MAX_INSTANCE_COUNT) { |
| LOG_ERR("Can not create instance - no more room: %u", obj_inst_id); |
| return NULL; |
| } |
| |
| /* Set default values */ |
| strncpy(device_table[index].device_id, CONFIG_LWM2M_GATEWAY_DEFAULT_DEVICE_ID, |
| CONFIG_LWM2M_GATEWAY_DEVICE_ID_MAX_STR_SIZE); |
| snprintk(device_table[index].prefix, CONFIG_LWM2M_GATEWAY_PREFIX_MAX_STR_SIZE, |
| CONFIG_LWM2M_GATEWAY_DEFAULT_DEVICE_PREFIX "%u", index); |
| strncpy(device_table[index].iot_device_objects, |
| CONFIG_LWM2M_GATEWAY_DEFAULT_IOT_DEVICE_OBJECTS, |
| CONFIG_LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_MAX_STR_SIZE); |
| |
| (void)memset(res[index], 0, sizeof(res[index][0]) * ARRAY_SIZE(res[index])); |
| init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index])); |
| |
| /* initialize instance resource data */ |
| INIT_OBJ_RES_DATA(LWM2M_GATEWAY_DEVICE_RID, res[index], i, res_inst[index], j, |
| device_table[index].device_id, |
| CONFIG_LWM2M_GATEWAY_DEVICE_ID_MAX_STR_SIZE); |
| INIT_OBJ_RES(LWM2M_GATEWAY_PREFIX_RID, res[index], i, res_inst[index], j, 1, false, true, |
| device_table[index].prefix, CONFIG_LWM2M_GATEWAY_PREFIX_MAX_STR_SIZE, NULL, |
| NULL, prefix_validation_cb, NULL, NULL); |
| INIT_OBJ_RES_DATA(LWM2M_GATEWAY_IOT_DEVICE_OBJECTS_RID, res[index], i, res_inst[index], j, |
| device_table[index].iot_device_objects, |
| sizeof(device_table[index].iot_device_objects)); |
| |
| inst[index].resources = res[index]; |
| inst[index].resource_count = i; |
| LOG_DBG("Created LWM2M gateway instance: %d", obj_inst_id); |
| return &inst[index]; |
| } |
| |
| static int lwm2m_gw_init(const struct device *dev) |
| { |
| int ret = 0; |
| |
| /* initialize the LwM2M Gateway field data */ |
| lwm2m_gw.obj_id = LWM2M_OBJECT_GATEWAY_ID; |
| lwm2m_gw.version_major = GATEWAY_VERSION_MAJOR; |
| lwm2m_gw.version_minor = GATEWAY_VERSION_MINOR; |
| lwm2m_gw.is_core = true; |
| lwm2m_gw.fields = fields; |
| lwm2m_gw.field_count = ARRAY_SIZE(fields); |
| lwm2m_gw.max_instance_count = MAX_INSTANCE_COUNT; |
| lwm2m_gw.create_cb = lwm2m_gw_create; |
| lwm2m_register_obj(&lwm2m_gw); |
| return ret; |
| } |
| |
| SYS_INIT(lwm2m_gw_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |