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/gpio.h>
17 #include <zephyr/drivers/sensor.h>
18 #include <zephyr/net/lwm2m.h>
19 #include "modules.h"
20 
21 #define APP_BANNER "Run LWM2M client"
22 
23 #define WAIT_TIME	K_SECONDS(10)
24 #define CONNECT_TIME	K_SECONDS(10)
25 
26 #define CLIENT_MANUFACTURER	"Zephyr"
27 #define CLIENT_MODEL_NUMBER	"OMA-LWM2M Sample Client"
28 #define CLIENT_SERIAL_NUMBER	"345000123"
29 #define CLIENT_FIRMWARE_VER	"1.0"
30 #define CLIENT_HW_VER		"1.0.1"
31 
32 static uint8_t bat_idx = LWM2M_DEVICE_PWR_SRC_TYPE_BAT_INT;
33 static int bat_mv = 3800;
34 static int bat_ma = 125;
35 static uint8_t usb_idx = LWM2M_DEVICE_PWR_SRC_TYPE_USB;
36 static int usb_mv = 5000;
37 static int usb_ma = 900;
38 static uint8_t bat_level = 95;
39 static uint8_t bat_status = LWM2M_DEVICE_BATTERY_STATUS_CHARGING;
40 static int mem_free = 15;
41 static int mem_total = 25;
42 
43 static struct lwm2m_ctx client_ctx;
44 
45 static const char *endpoint =
46 	(sizeof(CONFIG_LWM2M_APP_ID) > 1 ? CONFIG_LWM2M_APP_ID : CONFIG_BOARD);
47 
48 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
49 BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE,
50 		"Client ID length is too long");
51 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
52 
53 static struct k_sem quit_lock;
54 
device_reboot_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)55 static int device_reboot_cb(uint16_t obj_inst_id,
56 			    uint8_t *args, uint16_t args_len)
57 {
58 	LOG_INF("DEVICE: REBOOT");
59 	/* Add an error for testing */
60 	lwm2m_device_add_err(LWM2M_DEVICE_ERROR_LOW_POWER);
61 	/* Change the battery voltage for testing */
62 	lwm2m_set_s32(&LWM2M_OBJ(3, 0, 7, 0), (bat_mv - 1));
63 
64 	return 0;
65 }
66 
device_factory_default_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)67 static int device_factory_default_cb(uint16_t obj_inst_id,
68 				     uint8_t *args, uint16_t args_len)
69 {
70 	LOG_INF("DEVICE: FACTORY DEFAULT");
71 	/* Add an error for testing */
72 	lwm2m_device_add_err(LWM2M_DEVICE_ERROR_GPS_FAILURE);
73 	/* Change the USB current for testing */
74 	lwm2m_set_s32(&LWM2M_OBJ(3, 0, 8, 1), (usb_ma - 1));
75 
76 	return 0;
77 }
78 
79 
lwm2m_setup(void)80 static int lwm2m_setup(void)
81 {
82 	/* setup SECURITY object */
83 
84 	/* Server URL */
85 	lwm2m_set_string(&LWM2M_OBJ(0, 0, 0), CONFIG_LWM2M_APP_SERVER);
86 
87 	/* Security Mode */
88 	lwm2m_set_u8(&LWM2M_OBJ(0, 0, 2), IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? 0 : 3);
89 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
90 	lwm2m_set_string(&LWM2M_OBJ(0, 0, 3), endpoint);
91 	if (sizeof(CONFIG_LWM2M_APP_PSK) > 1) {
92 		char psk[1 + sizeof(CONFIG_LWM2M_APP_PSK) / 2];
93 		/* Need to skip the nul terminator from string */
94 		size_t len = hex2bin(CONFIG_LWM2M_APP_PSK, sizeof(CONFIG_LWM2M_APP_PSK) - 1, psk,
95 				     sizeof(psk));
96 		if (len <= 0) {
97 			return -EINVAL;
98 		}
99 		lwm2m_set_opaque(&LWM2M_OBJ(0, 0, 5), (void *)psk, len);
100 	}
101 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
102 
103 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
104 	/* Mark 1st instance of security object as a bootstrap server */
105 	lwm2m_set_u8(&LWM2M_OBJ(0, 0, 1), 1);
106 
107 	/* Create 2nd instance of security object needed for bootstrap */
108 	lwm2m_create_object_inst(&LWM2M_OBJ(0, 1));
109 #else
110 	/* Match Security object instance with a Server object instance with
111 	 * Short Server ID.
112 	 */
113 	lwm2m_set_u16(&LWM2M_OBJ(0, 0, 10), CONFIG_LWM2M_SERVER_DEFAULT_SSID);
114 	lwm2m_set_u16(&LWM2M_OBJ(1, 0, 0), CONFIG_LWM2M_SERVER_DEFAULT_SSID);
115 #endif
116 
117 	/* setup SERVER object */
118 
119 	/* setup DEVICE object */
120 
121 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 0), CLIENT_MANUFACTURER, sizeof(CLIENT_MANUFACTURER),
122 			  sizeof(CLIENT_MANUFACTURER), LWM2M_RES_DATA_FLAG_RO);
123 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 1), CLIENT_MODEL_NUMBER, sizeof(CLIENT_MODEL_NUMBER),
124 			  sizeof(CLIENT_MODEL_NUMBER), LWM2M_RES_DATA_FLAG_RO);
125 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 2), CLIENT_SERIAL_NUMBER, sizeof(CLIENT_SERIAL_NUMBER),
126 			  sizeof(CLIENT_SERIAL_NUMBER), LWM2M_RES_DATA_FLAG_RO);
127 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 3), CLIENT_FIRMWARE_VER, sizeof(CLIENT_FIRMWARE_VER),
128 			  sizeof(CLIENT_FIRMWARE_VER), LWM2M_RES_DATA_FLAG_RO);
129 	lwm2m_register_exec_callback(&LWM2M_OBJ(3, 0, 4), device_reboot_cb);
130 	lwm2m_register_exec_callback(&LWM2M_OBJ(3, 0, 5), device_factory_default_cb);
131 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 9), &bat_level, sizeof(bat_level), sizeof(bat_level), 0);
132 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 10), &mem_free, sizeof(mem_free), sizeof(mem_free), 0);
133 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 17), CONFIG_BOARD, sizeof(CONFIG_BOARD),
134 			  sizeof(CONFIG_BOARD), LWM2M_RES_DATA_FLAG_RO);
135 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 18), CLIENT_HW_VER, sizeof(CLIENT_HW_VER),
136 			  sizeof(CLIENT_HW_VER), LWM2M_RES_DATA_FLAG_RO);
137 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 20), &bat_status, sizeof(bat_status),
138 			  sizeof(bat_status), 0);
139 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 21), &mem_total, sizeof(mem_total),
140 			  sizeof(mem_total), 0);
141 
142 	/* add power source resource instances */
143 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 6, 0));
144 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 6, 0), &bat_idx, sizeof(bat_idx), sizeof(bat_idx), 0);
145 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 7, 0));
146 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 7, 0), &bat_mv, sizeof(bat_mv), sizeof(bat_mv), 0);
147 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 8, 0));
148 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 8, 0), &bat_ma, sizeof(bat_ma), sizeof(bat_ma), 0);
149 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 6, 1));
150 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 6, 1), &usb_idx, sizeof(usb_idx), sizeof(usb_idx), 0);
151 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 7, 1));
152 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 7, 1), &usb_mv, sizeof(usb_mv), sizeof(usb_mv), 0);
153 	lwm2m_create_res_inst(&LWM2M_OBJ(3, 0, 8, 1));
154 	lwm2m_set_res_buf(&LWM2M_OBJ(3, 0, 8, 1), &usb_ma, sizeof(usb_ma), sizeof(usb_ma), 0);
155 
156 	/* setup FIRMWARE object */
157 	if (IS_ENABLED(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT)) {
158 		init_firmware_update();
159 	}
160 
161 	/* setup TEMP SENSOR object */
162 	init_temp_sensor();
163 
164 	/* IPSO: Light Control object */
165 	init_led_device();
166 
167 	/* IPSO: Timer object */
168 	init_timer_object();
169 
170 	return 0;
171 }
172 
rd_client_event(struct lwm2m_ctx * client,enum lwm2m_rd_client_event client_event)173 static void rd_client_event(struct lwm2m_ctx *client,
174 			    enum lwm2m_rd_client_event client_event)
175 {
176 	switch (client_event) {
177 
178 	case LWM2M_RD_CLIENT_EVENT_NONE:
179 		/* do nothing */
180 		break;
181 
182 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE:
183 		LOG_DBG("Bootstrap registration failure!");
184 		break;
185 
186 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE:
187 		LOG_DBG("Bootstrap registration complete");
188 		break;
189 
190 	case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE:
191 		LOG_DBG("Bootstrap transfer complete");
192 		break;
193 
194 	case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE:
195 		LOG_DBG("Registration failure!");
196 		break;
197 
198 	case LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE:
199 		LOG_DBG("Registration complete");
200 		break;
201 
202 	case LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT:
203 		LOG_DBG("Registration timeout!");
204 		break;
205 
206 	case LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE:
207 		LOG_DBG("Registration update complete");
208 		break;
209 
210 	case LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE:
211 		LOG_DBG("Deregister failure!");
212 		break;
213 
214 	case LWM2M_RD_CLIENT_EVENT_DISCONNECT:
215 		LOG_DBG("Disconnected");
216 		break;
217 
218 	case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF:
219 		LOG_DBG("Queue mode RX window closed");
220 		break;
221 
222 	case LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED:
223 		LOG_DBG("LwM2M engine suspended");
224 		break;
225 
226 	case LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR:
227 		LOG_ERR("LwM2M engine reported a network error.");
228 		lwm2m_rd_client_stop(client, rd_client_event, true);
229 		break;
230 
231 	case LWM2M_RD_CLIENT_EVENT_REG_UPDATE:
232 		LOG_DBG("Registration update");
233 		break;
234 	case LWM2M_RD_CLIENT_EVENT_DEREGISTER:
235 		LOG_DBG("Client De-register");
236 		break;
237 	}
238 }
239 
observe_cb(enum lwm2m_observe_event event,struct lwm2m_obj_path * path,void * user_data)240 static void observe_cb(enum lwm2m_observe_event event,
241 		       struct lwm2m_obj_path *path, void *user_data)
242 {
243 	char buf[LWM2M_MAX_PATH_STR_SIZE];
244 
245 	switch (event) {
246 
247 	case LWM2M_OBSERVE_EVENT_OBSERVER_ADDED:
248 		LOG_INF("Observer added for %s", lwm2m_path_log_buf(buf, path));
249 		break;
250 
251 	case LWM2M_OBSERVE_EVENT_OBSERVER_REMOVED:
252 		LOG_INF("Observer removed for %s", lwm2m_path_log_buf(buf, path));
253 		break;
254 
255 	case LWM2M_OBSERVE_EVENT_NOTIFY_ACK:
256 		LOG_INF("Notify acknowledged for %s", lwm2m_path_log_buf(buf, path));
257 		break;
258 
259 	case LWM2M_OBSERVE_EVENT_NOTIFY_TIMEOUT:
260 		LOG_INF("Notify timeout for %s, trying registration update",
261 			lwm2m_path_log_buf(buf, path));
262 
263 		lwm2m_rd_client_update();
264 		break;
265 	}
266 }
267 
main(void)268 int main(void)
269 {
270 	uint32_t flags = IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) ?
271 				LWM2M_RD_CLIENT_FLAG_BOOTSTRAP : 0;
272 	int ret;
273 
274 	LOG_INF(APP_BANNER);
275 
276 	k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT);
277 
278 	ret = lwm2m_setup();
279 	if (ret < 0) {
280 		LOG_ERR("Cannot setup LWM2M fields (%d)", ret);
281 		return 0;
282 	}
283 
284 	(void)memset(&client_ctx, 0x0, sizeof(client_ctx));
285 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
286 	client_ctx.tls_tag = CONFIG_LWM2M_APP_TLS_TAG;
287 #endif
288 
289 	/* client_ctx.sec_obj_inst is 0 as a starting point */
290 	lwm2m_rd_client_start(&client_ctx, endpoint, flags, rd_client_event, observe_cb);
291 
292 	k_sem_take(&quit_lock, K_FOREVER);
293 	return 0;
294 }
295