1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * TODO:
10  * - Configurable CURRENT_TIME notification delay
11  */
12 
13 #define LOG_MODULE_NAME net_lwm2m_obj_device
14 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
18 
19 #include <string.h>
20 #include <stdio.h>
21 #include <zephyr/init.h>
22 
23 #include "lwm2m_object.h"
24 #include "lwm2m_engine.h"
25 
26 #define DEVICE_VERSION_MAJOR 1
27 #define DEVICE_VERSION_MINOR 0
28 
29 /* Device resource IDs */
30 #define DEVICE_MANUFACTURER_ID			0
31 #define DEVICE_MODEL_NUMBER_ID			1
32 #define DEVICE_SERIAL_NUMBER_ID			2
33 #define DEVICE_FIRMWARE_VERSION_ID		3
34 #define DEVICE_REBOOT_ID			4
35 #define DEVICE_FACTORY_DEFAULT_ID		5
36 #define DEVICE_AVAILABLE_POWER_SOURCES_ID	6
37 #define DEVICE_POWER_SOURCE_VOLTAGE_ID		7
38 #define DEVICE_POWER_SOURCE_CURRENT_ID		8
39 #define DEVICE_BATTERY_LEVEL_ID			9
40 #define DEVICE_MEMORY_FREE_ID			10
41 #define DEVICE_ERROR_CODE_ID			11
42 #define DEVICE_RESET_ERROR_CODE_ID		12
43 #define DEVICE_CURRENT_TIME_ID			13
44 #define DEVICE_UTC_OFFSET_ID			14
45 #define DEVICE_TIMEZONE_ID			15
46 #define DEVICE_SUPPORTED_BINDING_MODES_ID	16
47 #define DEVICE_TYPE_ID				17
48 #define DEVICE_HARDWARE_VERSION_ID		18
49 #define DEVICE_SOFTWARE_VERSION_ID		19
50 #define DEVICE_BATTERY_STATUS_ID		20
51 #define DEVICE_MEMORY_TOTAL_ID			21
52 #define DEVICE_EXT_DEV_INFO_ID			22
53 
54 #define DEVICE_MAX_ID				23
55 
56 #ifdef CONFIG_LWM2M_DEVICE_ERROR_CODE_MAX
57 #define DEVICE_ERROR_CODE_MAX	CONFIG_LWM2M_DEVICE_ERROR_CODE_MAX
58 #else
59 #define DEVICE_ERROR_CODE_MAX	10
60 #endif
61 
62 #ifdef CONFIG_LWM2M_DEVICE_PWRSRC_MAX
63 #define DEVICE_PWRSRC_MAX	CONFIG_LWM2M_DEVICE_PWRSRC_MAX
64 #else
65 #define DEVICE_PWRSRC_MAX	5
66 #endif
67 
68 #ifdef CONFIG_LWM2M_DEVICE_EXT_DEV_INFO_MAX
69 #define DEVICE_EXT_DEV_INFO_MAX CONFIG_LWM2M_DEVICE_EXT_DEV_INFO_MAX
70 #else
71 #define DEVICE_EXT_DEV_INFO_MAX	1
72 #endif
73 
74 #define DEVICE_STRING_SHORT	8
75 
76 #define DEVICE_SERVICE_INTERVAL_MS (MSEC_PER_SEC * 10)
77 
78 /*
79  * Calculate resource instances as follows:
80  * start with DEVICE_MAX_ID
81  * subtract EXEC resources (3)
82  * subtract MULTI resources because their counts include 0 resource (5)
83  * add 3x DEVICE_PWRSRC_MAX for POWER SOURCES resource instances
84  * add DEVICE_ERROR_CODE_MAX for ERROR CODE resource instances
85  * add DEVICE_EXT_DEV_INFO_MAX for EXT DEV INFO  resource instances
86  */
87 #define RESOURCE_INSTANCE_COUNT	(DEVICE_MAX_ID - 3 - 5 + \
88 				 DEVICE_PWRSRC_MAX*3 + DEVICE_ERROR_CODE_MAX + \
89 				 DEVICE_EXT_DEV_INFO_MAX)
90 
91 /* resource state variables */
92 static uint8_t  error_code_list[DEVICE_ERROR_CODE_MAX];
93 static time_t time_temp;
94 static time_t time_offset;
95 static uint8_t  binding_mode[DEVICE_STRING_SHORT];
96 
97 /* only 1 instance of device object exists */
98 static struct lwm2m_engine_obj device;
99 static struct lwm2m_engine_obj_field fields[] = {
100 	OBJ_FIELD_DATA(DEVICE_MANUFACTURER_ID, R_OPT, STRING),
101 	OBJ_FIELD_DATA(DEVICE_MODEL_NUMBER_ID, R_OPT, STRING),
102 	OBJ_FIELD_DATA(DEVICE_SERIAL_NUMBER_ID, R_OPT, STRING),
103 	OBJ_FIELD_DATA(DEVICE_FIRMWARE_VERSION_ID, R_OPT, STRING),
104 	OBJ_FIELD_EXECUTE_OPT(DEVICE_REBOOT_ID),
105 	OBJ_FIELD_EXECUTE_OPT(DEVICE_FACTORY_DEFAULT_ID),
106 	OBJ_FIELD_DATA(DEVICE_AVAILABLE_POWER_SOURCES_ID, R_OPT, U8),
107 	OBJ_FIELD_DATA(DEVICE_POWER_SOURCE_VOLTAGE_ID, R_OPT, S32),
108 	OBJ_FIELD_DATA(DEVICE_POWER_SOURCE_CURRENT_ID, R_OPT, S32),
109 	OBJ_FIELD_DATA(DEVICE_BATTERY_LEVEL_ID, R_OPT, U8),
110 	OBJ_FIELD_DATA(DEVICE_MEMORY_FREE_ID, R_OPT, S32),
111 	OBJ_FIELD_DATA(DEVICE_ERROR_CODE_ID, R, U8),
112 	OBJ_FIELD_EXECUTE_OPT(DEVICE_RESET_ERROR_CODE_ID),
113 	OBJ_FIELD_DATA(DEVICE_CURRENT_TIME_ID, RW_OPT, TIME),
114 	OBJ_FIELD_DATA(DEVICE_UTC_OFFSET_ID, RW_OPT, STRING),
115 	OBJ_FIELD_DATA(DEVICE_TIMEZONE_ID, RW_OPT, STRING),
116 	OBJ_FIELD_DATA(DEVICE_SUPPORTED_BINDING_MODES_ID, R, STRING),
117 	OBJ_FIELD_DATA(DEVICE_TYPE_ID, R_OPT, STRING),
118 	OBJ_FIELD_DATA(DEVICE_HARDWARE_VERSION_ID, R_OPT, STRING),
119 	OBJ_FIELD_DATA(DEVICE_SOFTWARE_VERSION_ID, R_OPT, STRING),
120 	OBJ_FIELD_DATA(DEVICE_BATTERY_STATUS_ID, R_OPT, U8),
121 	OBJ_FIELD_DATA(DEVICE_MEMORY_TOTAL_ID, R_OPT, S32),
122 	OBJ_FIELD_DATA(DEVICE_EXT_DEV_INFO_ID, R_OPT, OBJLNK)
123 };
124 
125 static struct lwm2m_engine_obj_inst inst;
126 static struct lwm2m_engine_res res[DEVICE_MAX_ID];
127 static struct lwm2m_engine_res_inst res_inst[RESOURCE_INSTANCE_COUNT];
128 
129 /* save error code resource instance point so we can easily clear later */
130 static struct lwm2m_engine_res_inst *error_code_ri;
131 
132 /* callbacks */
133 
reset_error_list_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)134 static int reset_error_list_cb(uint16_t obj_inst_id,
135 			       uint8_t *args, uint16_t args_len)
136 {
137 	int i;
138 
139 	/* "delete" error codes */
140 	for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) {
141 		error_code_list[i] = 0;
142 		error_code_ri[i].res_inst_id = RES_INSTANCE_NOT_CREATED;
143 	}
144 
145 	/* Default error code indicating no error */
146 	error_code_ri[0].res_inst_id = 0;
147 
148 	return 0;
149 }
150 
current_time_read_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)151 static void *current_time_read_cb(uint16_t obj_inst_id, uint16_t res_id,
152 				  uint16_t res_inst_id, size_t *data_len)
153 {
154 	time_temp = time_offset + (k_uptime_get() / 1000);
155 	*data_len = sizeof(time_temp);
156 
157 	return &time_temp;
158 }
159 
current_time_pre_write_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)160 static void *current_time_pre_write_cb(uint16_t obj_inst_id, uint16_t res_id,
161 				       uint16_t res_inst_id, size_t *data_len)
162 {
163 	*data_len = sizeof(time_temp);
164 	return &time_temp;
165 }
166 
current_time_post_write_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)167 static int current_time_post_write_cb(uint16_t obj_inst_id, uint16_t res_id,
168 				      uint16_t res_inst_id,
169 				      uint8_t *data, uint16_t data_len,
170 				      bool last_block, size_t total_size)
171 {
172 	if (data_len == 4U) {
173 		time_offset = *(uint32_t *)data - (uint32_t)(k_uptime_get() / 1000);
174 		return 0;
175 	} else if (data_len == 8U) {
176 		time_offset = *(time_t *)data - (time_t)(k_uptime_get() / 1000);
177 		return 0;
178 	}
179 
180 	LOG_ERR("unknown size %u", data_len);
181 	return -EINVAL;
182 }
183 
184 /* error code function */
185 
lwm2m_device_add_err(uint8_t error_code)186 int lwm2m_device_add_err(uint8_t error_code)
187 {
188 	int i;
189 
190 	for (i = 0; i < DEVICE_ERROR_CODE_MAX; i++) {
191 		if (error_code_list[i] == 0) {
192 			break;
193 		}
194 
195 		/* No duplicate error codes allowed */
196 		if (error_code_list[i] == error_code) {
197 			return 0;
198 		}
199 	}
200 
201 	if (i >= DEVICE_ERROR_CODE_MAX) {
202 		return -ENOMEM;
203 	}
204 
205 	error_code_list[i] = error_code;
206 	error_code_ri[i].res_inst_id = i;
207 	lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_ERROR_CODE_ID);
208 
209 	return 0;
210 }
211 
device_periodic_service(struct k_work * work)212 static void device_periodic_service(struct k_work *work)
213 {
214 	lwm2m_notify_observer(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_CURRENT_TIME_ID);
215 }
216 
lwm2m_update_device_service_period(uint32_t period_ms)217 int lwm2m_update_device_service_period(uint32_t period_ms)
218 {
219 	return lwm2m_engine_update_service_period(device_periodic_service, period_ms);
220 }
221 
device_create(uint16_t obj_inst_id)222 static struct lwm2m_engine_obj_inst *device_create(uint16_t obj_inst_id)
223 {
224 	int i = 0, j = 0;
225 
226 	init_res_instance(res_inst, ARRAY_SIZE(res_inst));
227 
228 	/* initialize instance resource data */
229 	INIT_OBJ_RES_OPTDATA(DEVICE_MANUFACTURER_ID, res, i, res_inst, j);
230 	INIT_OBJ_RES_OPTDATA(DEVICE_MODEL_NUMBER_ID, res, i, res_inst, j);
231 	INIT_OBJ_RES_OPTDATA(DEVICE_SERIAL_NUMBER_ID, res, i, res_inst, j);
232 	INIT_OBJ_RES_OPTDATA(DEVICE_FIRMWARE_VERSION_ID, res, i, res_inst, j);
233 	INIT_OBJ_RES_EXECUTE(DEVICE_REBOOT_ID, res, i, NULL);
234 	INIT_OBJ_RES_EXECUTE(DEVICE_FACTORY_DEFAULT_ID, res, i, NULL);
235 	INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_AVAILABLE_POWER_SOURCES_ID, res, i,
236 				   res_inst, j, DEVICE_PWRSRC_MAX, false);
237 	INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_POWER_SOURCE_VOLTAGE_ID, res, i,
238 				   res_inst, j, DEVICE_PWRSRC_MAX, false);
239 	INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_POWER_SOURCE_CURRENT_ID, res, i,
240 				   res_inst, j, DEVICE_PWRSRC_MAX, false);
241 	INIT_OBJ_RES_OPTDATA(DEVICE_BATTERY_LEVEL_ID, res, i, res_inst, j);
242 	INIT_OBJ_RES_OPTDATA(DEVICE_MEMORY_FREE_ID, res, i, res_inst, j);
243 	error_code_ri = &res_inst[j];
244 	INIT_OBJ_RES_MULTI_DATA(DEVICE_ERROR_CODE_ID, res, i,
245 				res_inst, j, DEVICE_ERROR_CODE_MAX, false,
246 				error_code_list, sizeof(*error_code_list));
247 	INIT_OBJ_RES_EXECUTE(DEVICE_RESET_ERROR_CODE_ID, res, i,
248 			     reset_error_list_cb);
249 	INIT_OBJ_RES_OPT(DEVICE_CURRENT_TIME_ID, res, i, res_inst, j, 1, false,
250 			 true, current_time_read_cb, current_time_pre_write_cb,
251 			 NULL, current_time_post_write_cb, NULL);
252 	INIT_OBJ_RES_OPTDATA(DEVICE_UTC_OFFSET_ID, res, i, res_inst, j);
253 	INIT_OBJ_RES_OPTDATA(DEVICE_TIMEZONE_ID, res, i, res_inst, j);
254 	INIT_OBJ_RES_DATA(DEVICE_SUPPORTED_BINDING_MODES_ID, res, i,
255 			  res_inst, j, binding_mode, DEVICE_STRING_SHORT);
256 	INIT_OBJ_RES_OPTDATA(DEVICE_TYPE_ID, res, i, res_inst, j);
257 	INIT_OBJ_RES_OPTDATA(DEVICE_HARDWARE_VERSION_ID, res, i, res_inst, j);
258 	INIT_OBJ_RES_OPTDATA(DEVICE_SOFTWARE_VERSION_ID, res, i, res_inst, j);
259 	INIT_OBJ_RES_OPTDATA(DEVICE_BATTERY_STATUS_ID, res, i, res_inst, j);
260 	INIT_OBJ_RES_OPTDATA(DEVICE_MEMORY_TOTAL_ID, res, i, res_inst, j);
261 	INIT_OBJ_RES_MULTI_OPTDATA(DEVICE_EXT_DEV_INFO_ID, res, i, res_inst, j,
262 				   DEVICE_EXT_DEV_INFO_MAX, false);
263 
264 	inst.resources = res;
265 	inst.resource_count = i;
266 
267 	LOG_DBG("Create LWM2M device instance: %d", obj_inst_id);
268 	return &inst;
269 }
270 
lwm2m_device_init(void)271 static int lwm2m_device_init(void)
272 {
273 	struct lwm2m_engine_obj_inst *obj_inst = NULL;
274 	int ret = 0;
275 
276 	/* Set default values */
277 	time_offset = 0U;
278 	lwm2m_engine_get_binding(binding_mode);
279 
280 	/* initialize the device field data */
281 	device.obj_id = LWM2M_OBJECT_DEVICE_ID;
282 	device.version_major = DEVICE_VERSION_MAJOR;
283 	device.version_minor = DEVICE_VERSION_MINOR;
284 	device.is_core = true;
285 	device.fields = fields;
286 	device.field_count = ARRAY_SIZE(fields);
287 	device.max_instance_count = 1U;
288 	device.create_cb = device_create;
289 	lwm2m_register_obj(&device);
290 
291 	/* auto create the only instance */
292 	ret = lwm2m_create_obj_inst(LWM2M_OBJECT_DEVICE_ID, 0, &obj_inst);
293 	if (ret < 0) {
294 		LOG_DBG("Create LWM2M instance 0 error: %d", ret);
295 	}
296 
297 	/* Create the default error code resource instance */
298 	lwm2m_device_add_err(0);
299 
300 	/* call device_periodic_service() every 10 seconds */
301 	ret = lwm2m_engine_add_service(device_periodic_service,
302 				       DEVICE_SERVICE_INTERVAL_MS);
303 	return ret;
304 }
305 
306 SYS_INIT(lwm2m_device_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
307