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