1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2017-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define LOG_MODULE_NAME net_lwm2m_client_app
9 #define LOG_LEVEL LOG_LEVEL_DBG
10 
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
13 
14 #include <zephyr/drivers/hwinfo.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/drivers/sensor.h>
17 #include <zephyr/net/lwm2m.h>
18 #include <zephyr/net/conn_mgr_monitor.h>
19 #include <zephyr/net/conn_mgr_connectivity.h>
20 #include "modules.h"
21 #include "lwm2m_resource_ids.h"
22 
23 #define APP_BANNER "Run LWM2M client"
24 
25 #define WAIT_TIME	K_SECONDS(10)
26 #define CONNECT_TIME	K_SECONDS(10)
27 
28 #define CLIENT_MANUFACTURER	"Zephyr"
29 #define CLIENT_MODEL_NUMBER	"OMA-LWM2M Sample Client"
30 #define CLIENT_SERIAL_NUMBER	"345000123"
31 #define CLIENT_FIRMWARE_VER	"1.0"
32 #define CLIENT_HW_VER		"1.0.1"
33 #define TEMP_SENSOR_UNITS	"Celcius"
34 
35 /* Macros used to subscribe to specific Zephyr NET management events. */
36 #define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED)
37 #define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR)
38 
39 static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT;
40 static int bat_mv = 3800;
41 static int bat_ma = 125;
42 static uint8_t usb_idx = LWM2M_DEVICE_PWR_SRC_TYPE_USB;
43 static int usb_mv = 5000;
44 static int usb_ma = 900;
45 static uint8_t bat_level = 95;
46 static uint8_t bat_status = LWM2M_DEVICE_BATTERY_STATUS_CHARGING;
47 static int mem_free = 15;
48 static int mem_total = 25;
49 static double min_range = 0.0;
50 static double max_range = 100;
51 
52 static struct lwm2m_ctx client_ctx;
53 
54 static const char *endpoint =
55 	(sizeof(CONFIG_LWM2M_APP_ID) > 1 ? CONFIG_LWM2M_APP_ID : CONFIG_BOARD);
56 
57 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
58 BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE,
59 		"Client ID length is too long");
60 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
61 
62 static struct k_sem quit_lock;
63 
64 /* Zephyr NET management event callback structures. */
65 static struct net_mgmt_event_callback l4_cb;
66 static struct net_mgmt_event_callback conn_cb;
67 
68 static K_SEM_DEFINE(network_connected_sem, 0, 1);
69 
device_reboot_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)70 static int device_reboot_cb(uint16_t obj_inst_id,
71 			    uint8_t *args, uint16_t args_len)
72 {
73 	LOG_INF("DEVICE: REBOOT");
74 	/* Add an error for testing */
75 	lwm2m_device_add_err(LWM2M_DEVICE_ERROR_LOW_POWER);
76 	/* Change the battery voltage for testing */
77 	lwm2m_set_s32(&LWM2M_OBJ(3, 0, 7, 0), (bat_mv - 1));
78 
79 	return 0;
80 }
81 
device_factory_default_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)82 static int device_factory_default_cb(uint16_t obj_inst_id,
83 				     uint8_t *args, uint16_t args_len)
84 {
85 	LOG_INF("DEVICE: FACTORY DEFAULT");
86 	/* Add an error for testing */
87 	lwm2m_device_add_err(LWM2M_DEVICE_ERROR_GPS_FAILURE);
88 	/* Change the USB current for testing */
89 	lwm2m_set_s32(&LWM2M_OBJ(3, 0, 8, 1), (usb_ma - 1));
90 
91 	return 0;
92 }
93 
lwm2m_setup(void)94 static int lwm2m_setup(void)
95 {
96 	struct lwm2m_res_item temp_sensor_items[] = {
97 		{&LWM2M_OBJ(IPSO_OBJECT_TEMP_SENSOR_ID, 0, MIN_RANGE_VALUE_RID), &min_range,
98 		 sizeof(min_range)},
99 		{&LWM2M_OBJ(IPSO_OBJECT_TEMP_SENSOR_ID, 0, MAX_RANGE_VALUE_RID), &max_range,
100 		 sizeof(max_range)},
101 		{&LWM2M_OBJ(IPSO_OBJECT_TEMP_SENSOR_ID, 0, SENSOR_UNITS_RID), TEMP_SENSOR_UNITS,
102 		 sizeof(TEMP_SENSOR_UNITS)}
103 	};
104 
105 	/* setup SECURITY object */
106 
107 	/* Server URL */
108 	lwm2m_set_string(&LWM2M_OBJ(0, 0, 0), CONFIG_LWM2M_APP_SERVER);
109 
110 	/* Security Mode */
111 	lwm2m_set_u8(&LWM2M_OBJ(0, 0, 2), IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? 0 : 3);
112 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
113 	lwm2m_set_string(&LWM2M_OBJ(0, 0, 3), endpoint);
114 	if (sizeof(CONFIG_LWM2M_APP_PSK) > 1) {
115 		char psk[1 + sizeof(CONFIG_LWM2M_APP_PSK) / 2];
116 		/* Need to skip the nul terminator from string */
117 		size_t len = hex2bin(CONFIG_LWM2M_APP_PSK, sizeof(CONFIG_LWM2M_APP_PSK) - 1, psk,
118 				     sizeof(psk));
119 		if (len <= 0) {
120 			return -EINVAL;
121 		}
122 		lwm2m_set_opaque(&LWM2M_OBJ(0, 0, 5), (void *)psk, len);
123 	}
124 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
125 
126 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
127 	/* Mark 1st instance of security object as a bootstrap server */
128 	lwm2m_set_u8(&LWM2M_OBJ(0, 0, 1), 1);
129 #else
130 	/* Match Security object instance with a Server object instance with
131 	 * Short Server ID.
132 	 */
133 	lwm2m_set_u16(&LWM2M_OBJ(0, 0, 10), CONFIG_LWM2M_SERVER_DEFAULT_SSID);
134 	lwm2m_set_u16(&LWM2M_OBJ(1, 0, 0), CONFIG_LWM2M_SERVER_DEFAULT_SSID);
135 #endif
136 
137 	/* setup SERVER object */
138 
139 	/* setup DEVICE object */
140 
141 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 0), CLIENT_MANUFACTURER, sizeof(CLIENT_MANUFACTURER),
142 			  sizeof(CLIENT_MANUFACTURER), LWM2M_RES_DATA_FLAG_RO);
143 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 1), CLIENT_MODEL_NUMBER, sizeof(CLIENT_MODEL_NUMBER),
144 			  sizeof(CLIENT_MODEL_NUMBER), LWM2M_RES_DATA_FLAG_RO);
145 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 2), CLIENT_SERIAL_NUMBER, sizeof(CLIENT_SERIAL_NUMBER),
146 			  sizeof(CLIENT_SERIAL_NUMBER), LWM2M_RES_DATA_FLAG_RO);
147 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 3), CLIENT_FIRMWARE_VER, sizeof(CLIENT_FIRMWARE_VER),
148 			  sizeof(CLIENT_FIRMWARE_VER), LWM2M_RES_DATA_FLAG_RO);
149 	lwm2m_register_exec_callback(&LWM2M_OBJ(3, 0, 4), device_reboot_cb);
150 	lwm2m_register_exec_callback(&LWM2M_OBJ(3, 0, 5), device_factory_default_cb);
151 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 9), &bat_level, sizeof(bat_level), sizeof(bat_level), 0);
152 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 10), &mem_free, sizeof(mem_free), sizeof(mem_free), 0);
153 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 17), CONFIG_BOARD, sizeof(CONFIG_BOARD),
154 			  sizeof(CONFIG_BOARD), LWM2M_RES_DATA_FLAG_RO);
155 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 18), CLIENT_HW_VER, sizeof(CLIENT_HW_VER),
156 			  sizeof(CLIENT_HW_VER), LWM2M_RES_DATA_FLAG_RO);
157 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 20), &bat_status, sizeof(bat_status),
158 			  sizeof(bat_status), 0);
159 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 21), &mem_total, sizeof(mem_total),
160 			  sizeof(mem_total), 0);
161 
162 	/* add power source resource instances */
163 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 6, 0));
164 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 6, 0), &bat_idx, sizeof(bat_idx), sizeof(bat_idx), 0);
165 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 7, 0));
166 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 7, 0), &bat_mv, sizeof(bat_mv), sizeof(bat_mv), 0);
167 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 8, 0));
168 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 8, 0), &bat_ma, sizeof(bat_ma), sizeof(bat_ma), 0);
169 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 6, 1));
170 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 6, 1), &usb_idx, sizeof(usb_idx), sizeof(usb_idx), 0);
171 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 7, 1));
172 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 7, 1), &usb_mv, sizeof(usb_mv), sizeof(usb_mv), 0);
173 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 8, 1));
174 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 8, 1), &usb_ma, sizeof(usb_ma), sizeof(usb_ma), 0);
175 
176 	/* setup FIRMWARE object */
177 	if (IS_ENABLED(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)) {
178 		init_firmware_update();
179 	}
180 
181 	/* setup TEMP SENSOR object */
182 	init_temp_sensor();
183 
184 	/* Set multiple TEMP SENSOR resource values in one function call. */
185 	int err = lwm2m_set_bulk(temp_sensor_items, ARRAY_SIZE(temp_sensor_items));
186 
187 	if (err) {
188 		LOG_ERR("Failed to set TEMP SENSOR resources");
189 		return err;
190 	}
191 
192 	/* IPSO: Light Control object */
193 	init_led_device();
194 
195 	/* IPSO: Timer object */
196 	init_timer_object();
197 
198 	return 0;
199 }
200 
rd_client_event(struct lwm2m_ctx * client,enum lwm2m_rd_client_event client_event)201 static void rd_client_event(struct lwm2m_ctx *client,
202 			    enum lwm2m_rd_client_event client_event)
203 {
204 	switch (client_event) {
205 
206 	case LWM2M_RD_CLIENT_EVENT_NONE:
207 		/* do nothing */
208 		break;
209 
210 	case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED:
211 		LOG_DBG("LwM2M server disabled");
212 		break;
213 
214 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE:
215 		LOG_DBG("Bootstrap registration failure!");
216 		break;
217 
218 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE:
219 		LOG_DBG("Bootstrap registration complete");
220 		break;
221 
222 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE:
223 		LOG_DBG("Bootstrap transfer complete");
224 		break;
225 
226 	case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE:
227 		LOG_DBG("Registration failure!");
228 		break;
229 
230 	case LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE:
231 		LOG_DBG("Registration complete");
232 		break;
233 
234 	case LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT:
235 		LOG_DBG("Registration timeout!");
236 		break;
237 
238 	case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE:
239 		LOG_DBG("Registration update complete");
240 		break;
241 
242 	case LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE:
243 		LOG_DBG("Deregister failure!");
244 		break;
245 
246 	case LWM2M_RD_CLIENT_EVENT_DISCONNECT:
247 		LOG_DBG("Disconnected");
248 		break;
249 
250 	case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF:
251 		LOG_DBG("Queue mode RX window closed");
252 		break;
253 
254 	case LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED:
255 		LOG_DBG("LwM2M engine suspended");
256 		break;
257 
258 	case LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR:
259 		LOG_ERR("LwM2M engine reported a network error.");
260 		lwm2m_rd_client_stop(client, rd_client_event, true);
261 		break;
262 
263 	case LWM2M_RD_CLIENT_EVENT_REG_UPDATE:
264 		LOG_DBG("Registration update");
265 		break;
266 	case LWM2M_RD_CLIENT_EVENT_DEREGISTER:
267 		LOG_DBG("Client De-register");
268 		break;
269 	}
270 }
271 
socket_state(int fd,enum lwm2m_socket_states state)272 static void socket_state(int fd, enum lwm2m_socket_states state)
273 {
274 	(void) fd;
275 	switch (state) {
276 	case LWM2M_SOCKET_STATE_ONGOING:
277 		LOG_DBG("LWM2M_SOCKET_STATE_ONGOING");
278 		break;
279 	case LWM2M_SOCKET_STATE_ONE_RESPONSE:
280 		LOG_DBG("LWM2M_SOCKET_STATE_ONE_RESPONSE");
281 		break;
282 	case LWM2M_SOCKET_STATE_LAST:
283 		LOG_DBG("LWM2M_SOCKET_STATE_LAST");
284 		break;
285 	case LWM2M_SOCKET_STATE_NO_DATA:
286 		LOG_DBG("LWM2M_SOCKET_STATE_NO_DATA");
287 		break;
288 	}
289 }
290 
observe_cb(enum lwm2m_observe_event event,struct lwm2m_obj_path * path,void * user_data)291 static void observe_cb(enum lwm2m_observe_event event,
292 		       struct lwm2m_obj_path *path, void *user_data)
293 {
294 	char buf[LWM2M_MAX_PATH_STR_SIZE];
295 
296 	switch (event) {
297 
298 	case LWM2M_OBSERVE_EVENT_OBSERVER_ADDED:
299 		LOG_INF("Observer added for %s", lwm2m_path_log_buf(buf, path));
300 		break;
301 
302 	case LWM2M_OBSERVE_EVENT_OBSERVER_REMOVED:
303 		LOG_INF("Observer removed for %s", lwm2m_path_log_buf(buf, path));
304 		break;
305 
306 	case LWM2M_OBSERVE_EVENT_NOTIFY_ACK:
307 		LOG_INF("Notify acknowledged for %s", lwm2m_path_log_buf(buf, path));
308 		break;
309 
310 	case LWM2M_OBSERVE_EVENT_NOTIFY_TIMEOUT:
311 		LOG_INF("Notify timeout for %s, trying registration update",
312 			lwm2m_path_log_buf(buf, path));
313 
314 		lwm2m_rd_client_update();
315 		break;
316 	}
317 }
318 
on_net_event_l4_disconnected(void)319 static void on_net_event_l4_disconnected(void)
320 {
321 	LOG_INF("Disconnected from network");
322 	lwm2m_engine_pause();
323 }
324 
on_net_event_l4_connected(void)325 static void on_net_event_l4_connected(void)
326 {
327 	LOG_INF("Connected to network");
328 	k_sem_give(&network_connected_sem);
329 	lwm2m_engine_resume();
330 }
331 
l4_event_handler(struct net_mgmt_event_callback * cb,uint32_t event,struct net_if * iface)332 static void l4_event_handler(struct net_mgmt_event_callback *cb,
333 			     uint32_t event,
334 			     struct net_if *iface)
335 {
336 	switch (event) {
337 	case NET_EVENT_L4_CONNECTED:
338 		LOG_INF("IP Up");
339 		on_net_event_l4_connected();
340 		break;
341 	case NET_EVENT_L4_DISCONNECTED:
342 		LOG_INF("IP down");
343 		on_net_event_l4_disconnected();
344 		break;
345 	default:
346 		break;
347 	}
348 }
349 
connectivity_event_handler(struct net_mgmt_event_callback * cb,uint32_t event,struct net_if * iface)350 static void connectivity_event_handler(struct net_mgmt_event_callback *cb,
351 				       uint32_t event,
352 				       struct net_if *iface)
353 {
354 	if (event == NET_EVENT_CONN_IF_FATAL_ERROR) {
355 		LOG_ERR("Fatal error received from the connectivity layer");
356 		return;
357 	}
358 }
359 
main(void)360 int main(void)
361 {
362 	uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ?
363 				LWM2M_RD_CLIENT_FLAG_BOOTSTRAP : 0;
364 	int ret;
365 
366 	LOG_INF(APP_BANNER);
367 
368 	k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT);
369 
370 	if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
371 		/* Setup handler for Zephyr NET Connection Manager events. */
372 		net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK);
373 		net_mgmt_add_event_callback(&l4_cb);
374 
375 		/* Setup handler for Zephyr NET Connection Manager Connectivity layer. */
376 		net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler,
377 					     CONN_LAYER_EVENT_MASK);
378 		net_mgmt_add_event_callback(&conn_cb);
379 
380 		ret = net_if_up(net_if_get_default());
381 
382 		if (ret < 0 && ret != -EALREADY) {
383 			LOG_ERR("net_if_up, error: %d", ret);
384 			return ret;
385 		}
386 
387 		(void)conn_mgr_if_connect(net_if_get_default());
388 
389 		k_sem_take(&network_connected_sem, K_FOREVER);
390 	}
391 
392 	ret = lwm2m_setup();
393 	if (ret < 0) {
394 		LOG_ERR("Cannot setup LWM2M fields (%d)", ret);
395 		return 0;
396 	}
397 
398 	(void)memset(&client_ctx, 0x0, sizeof(client_ctx));
399 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
400 	client_ctx.tls_tag = CONFIG_LWM2M_APP_TLS_TAG;
401 #endif
402 	client_ctx.set_socket_state = socket_state;
403 
404 	/* client_ctx.sec_obj_inst is 0 as a starting point */
405 	lwm2m_rd_client_start(&client_ctx, endpoint, flags, rd_client_event, observe_cb);
406 
407 	k_sem_take(&quit_lock, K_FOREVER);
408 	return 0;
409 }
410