1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "os/mynewt.h"
21 #include <bsp/bsp.h>
22 #include <hal/hal_gpio.h>
23 #include <hal/hal_flash.h>
24 #include <console/console.h>
25 #include <log/log.h>
26 #include <stats/stats.h>
27 #include <config/config.h>
28 #if MYNEWT_VAL(SPLIT_LOADER)
29 #include "split/split.h"
30 #endif
31 #include <bootutil/image.h>
32 #include <img_mgmt/img_mgmt.h>
33 #include <mgmt/mgmt.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <reboot/log_reboot.h>
37 #include <oic/oc_api.h>
38 #include <cborattr/cborattr.h>
39
40 #ifndef ARCH_sim
41 /* BLE */
42 #include "nimble/ble.h"
43 #include "host/ble_hs.h"
44 #include "host/util/util.h"
45 #include "services/gap/ble_svc_gap.h"
46
47 #include <oic/oc_gatt.h>
48
49 /* Application-specified header. */
50 #include "omp_svr.h"
51
52 #else
53 #include <mcu/mcu_sim.h>
54 #endif /* !ARCH_sim */
55
56 /* Task 1 */
57 #define TASK1_PRIO (8)
58 #define TASK1_STACK_SIZE OS_STACK_ALIGN(192)
59 static struct os_task task1;
60 static volatile int g_task1_loops;
61
62 /* Task 2 */
63 #define TASK2_PRIO (9)
64 #define TASK2_STACK_SIZE OS_STACK_ALIGN(64)
65 static struct os_task task2;
66
67 static volatile int g_task2_loops;
68
69 /* Global test semaphore */
70 static struct os_sem g_test_sem;
71
72 /* For LED toggling */
73 static int g_led_pin;
74
75 STATS_SECT_START(gpio_stats)
76 STATS_SECT_ENTRY(toggles)
77 STATS_SECT_END
78
79 static STATS_SECT_DECL(gpio_stats) g_stats_gpio_toggle;
80
81 STATS_NAME_START(gpio_stats)
82 STATS_NAME(gpio_stats, toggles)
83 STATS_NAME_END(gpio_stats)
84
85 static char *test_conf_get(int argc, char **argv, char *val, int max_len);
86 static int test_conf_set(int argc, char **argv, char *val);
87 static int test_conf_commit(void);
88 static int test_conf_export(void (*export_func)(char *name, char *val),
89 enum conf_export_tgt tgt);
90
91 static struct conf_handler test_conf_handler = {
92 .ch_name = "test",
93 .ch_get = test_conf_get,
94 .ch_set = test_conf_set,
95 .ch_commit = test_conf_commit,
96 .ch_export = test_conf_export
97 };
98
99 static uint8_t test8;
100 static uint8_t test8_shadow;
101 static char test_str[32];
102
103 static char *
test_conf_get(int argc,char ** argv,char * buf,int max_len)104 test_conf_get(int argc, char **argv, char *buf, int max_len)
105 {
106 if (argc == 1) {
107 if (!strcmp(argv[0], "8")) {
108 return conf_str_from_value(CONF_INT8, &test8, buf, max_len);
109 } else if (!strcmp(argv[0], "str")) {
110 return test_str;
111 }
112 }
113 return NULL;
114 }
115
116 static int
test_conf_set(int argc,char ** argv,char * val)117 test_conf_set(int argc, char **argv, char *val)
118 {
119 if (argc == 1) {
120 if (!strcmp(argv[0], "8")) {
121 return CONF_VALUE_SET(val, CONF_INT8, test8_shadow);
122 } else if (!strcmp(argv[0], "str")) {
123 return CONF_VALUE_SET(val, CONF_STRING, test_str);
124 }
125 }
126 return OS_ENOENT;
127 }
128
129 static int
test_conf_commit(void)130 test_conf_commit(void)
131 {
132 test8 = test8_shadow;
133
134 return 0;
135 }
136
137 static int
test_conf_export(void (* func)(char * name,char * val),enum conf_export_tgt tgt)138 test_conf_export(void (*func)(char *name, char *val), enum conf_export_tgt tgt)
139 {
140 char buf[4];
141
142 conf_str_from_value(CONF_INT8, &test8, buf, sizeof(buf));
143 func("test/8", buf);
144 func("test/str", test_str);
145 return 0;
146 }
147
148 #ifndef ARCH_sim
149 static int omp_svr_gap_event(struct ble_gap_event *event, void *arg);
150
151 /**
152 * Logs information about a connection to the console.
153 */
154 static void
omp_svr_print_conn_desc(struct ble_gap_conn_desc * desc)155 omp_svr_print_conn_desc(struct ble_gap_conn_desc *desc)
156 {
157 MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
158 desc->conn_handle, desc->our_ota_addr.type);
159 print_addr(desc->our_ota_addr.val);
160 MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
161 desc->our_id_addr.type);
162 print_addr(desc->our_id_addr.val);
163 MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
164 desc->peer_ota_addr.type);
165 print_addr(desc->peer_ota_addr.val);
166 MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
167 desc->peer_id_addr.type);
168 print_addr(desc->peer_id_addr.val);
169 MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
170 "encrypted=%d authenticated=%d bonded=%d\n",
171 desc->conn_itvl, desc->conn_latency,
172 desc->supervision_timeout,
173 desc->sec_state.encrypted,
174 desc->sec_state.authenticated,
175 desc->sec_state.bonded);
176 }
177
178 /**
179 * Enables advertising with the following parameters:
180 * o General discoverable mode.
181 * o Undirected connectable mode.
182 */
183 static void
omp_svr_advertise(void)184 omp_svr_advertise(void)
185 {
186 uint8_t own_addr_type;
187 struct ble_gap_adv_params adv_params;
188 struct ble_hs_adv_fields fields;
189 const char *name;
190 int rc;
191
192 /* Figure out address to use while advertising (no privacy for now) */
193 rc = ble_hs_id_infer_auto(0, &own_addr_type);
194 if (rc != 0) {
195 MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
196 return;
197 }
198
199 /**
200 * Set the advertisement data included in our advertisements:
201 * o Flags (indicates advertisement type and other general info).
202 * o Advertising tx power.
203 * o Device name.
204 * o 16-bit service UUIDs (alert notifications).
205 */
206
207 memset(&fields, 0, sizeof fields);
208
209 /* Advertise two flags:
210 * o Discoverability in forthcoming advertisement (general)
211 * o BLE-only (BR/EDR unsupported).
212 */
213 fields.flags = BLE_HS_ADV_F_DISC_GEN |
214 BLE_HS_ADV_F_BREDR_UNSUP;
215
216 /* Indicate that the TX power level field should be included; have the
217 * stack fill this value automatically. This is done by assiging the
218 * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
219 */
220 fields.tx_pwr_lvl_is_present = 1;
221 fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
222
223 name = ble_svc_gap_device_name();
224 fields.name = (uint8_t *)name;
225 fields.name_len = strlen(name);
226 fields.name_is_complete = 1;
227
228 fields.uuids16 = (ble_uuid16_t[]){
229 BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
230 };
231 fields.num_uuids16 = 1;
232 fields.uuids16_is_complete = 1;
233
234 rc = ble_gap_adv_set_fields(&fields);
235 if (rc != 0) {
236 MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
237 return;
238 }
239
240 /* Begin advertising. */
241 memset(&adv_params, 0, sizeof adv_params);
242 adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
243 adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
244 rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
245 &adv_params, omp_svr_gap_event, NULL);
246 if (rc != 0) {
247 MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
248 return;
249 }
250 }
251
252 /**
253 * The nimble host executes this callback when a GAP event occurs. The
254 * application associates a GAP event callback with each connection that forms.
255 * omp_svr uses the same callback for all connections.
256 *
257 * @param event The type of event being signalled.
258 * @param ctxt Various information pertaining to the event.
259 * @param arg Application-specified argument; unuesd by
260 * omp_svr.
261 *
262 * @return 0 if the application successfully handled the
263 * event; nonzero on failure. The semantics
264 * of the return code is specific to the
265 * particular GAP event being signalled.
266 */
267 static int
omp_svr_gap_event(struct ble_gap_event * event,void * arg)268 omp_svr_gap_event(struct ble_gap_event *event, void *arg)
269 {
270 struct ble_gap_conn_desc desc;
271 int rc;
272
273 switch (event->type) {
274 case BLE_GAP_EVENT_CONNECT:
275 /* A new connection was established or a connection attempt failed. */
276 MODLOG_DFLT(INFO, "connection %s; status=%d ",
277 event->connect.status == 0 ? "established" : "failed",
278 event->connect.status);
279 if (event->connect.status == 0) {
280 rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
281 assert(rc == 0);
282 omp_svr_print_conn_desc(&desc);
283
284 }
285 MODLOG_DFLT(INFO, "\n");
286
287 if (event->connect.status != 0) {
288 /* Connection failed; resume advertising. */
289 omp_svr_advertise();
290 }
291 return 0;
292
293 case BLE_GAP_EVENT_DISCONNECT:
294 MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
295 omp_svr_print_conn_desc(&event->disconnect.conn);
296 MODLOG_DFLT(INFO, "\n");
297
298 /* Connection terminated; resume advertising. */
299 omp_svr_advertise();
300 return 0;
301
302 case BLE_GAP_EVENT_CONN_UPDATE:
303 /* The central has updated the connection parameters. */
304 MODLOG_DFLT(INFO, "connection updated; status=%d ",
305 event->conn_update.status);
306 rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
307 assert(rc == 0);
308 omp_svr_print_conn_desc(&desc);
309 MODLOG_DFLT(INFO, "\n");
310 return 0;
311
312 case BLE_GAP_EVENT_ADV_COMPLETE:
313 MODLOG_DFLT(INFO, "advertise complete; reason=%d",
314 event->adv_complete.reason);
315 omp_svr_advertise();
316 return 0;
317
318 case BLE_GAP_EVENT_ENC_CHANGE:
319 /* Encryption has been enabled or disabled for this connection. */
320 MODLOG_DFLT(INFO, "encryption change event; status=%d ",
321 event->enc_change.status);
322 rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
323 assert(rc == 0);
324 omp_svr_print_conn_desc(&desc);
325 MODLOG_DFLT(INFO, "\n");
326 return 0;
327
328 case BLE_GAP_EVENT_SUBSCRIBE:
329 MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
330 "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
331 event->subscribe.conn_handle,
332 event->subscribe.attr_handle,
333 event->subscribe.reason,
334 event->subscribe.prev_notify,
335 event->subscribe.cur_notify,
336 event->subscribe.prev_indicate,
337 event->subscribe.cur_indicate);
338 return 0;
339
340 case BLE_GAP_EVENT_MTU:
341 MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
342 event->mtu.conn_handle,
343 event->mtu.channel_id,
344 event->mtu.value);
345 return 0;
346
347 case BLE_GAP_EVENT_REPEAT_PAIRING:
348 /* We already have a bond with the peer, but it is attempting to
349 * establish a new secure link. This app sacrifices security for
350 * convenience: just throw away the old bond and accept the new link.
351 */
352
353 /* Delete the old bond. */
354 rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
355 assert(rc == 0);
356 ble_store_util_delete_peer(&desc.peer_id_addr);
357
358 /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
359 * continue with the pairing operation.
360 */
361 return BLE_GAP_REPEAT_PAIRING_RETRY;
362 }
363
364 return 0;
365 }
366
367 static void
omp_svr_on_reset(int reason)368 omp_svr_on_reset(int reason)
369 {
370 MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
371 }
372
373 static void
omp_svr_on_sync(void)374 omp_svr_on_sync(void)
375 {
376 int rc;
377
378 /* Make sure we have proper identity address set (public preferred) */
379 rc = ble_hs_util_ensure_addr(0);
380 assert(rc == 0);
381
382 /* Begin advertising. */
383 omp_svr_advertise();
384 }
385 #endif /* ARCH_sim */
386
387 void
task1_handler(void * arg)388 task1_handler(void *arg)
389 {
390 struct os_task *t;
391 int prev_pin_state, curr_pin_state;
392 struct image_version ver;
393 char ver_str[IMG_MGMT_VER_MAX_STR_LEN];
394 int rc;
395
396 /* Set the led pin for the E407 devboard */
397 g_led_pin = LED_BLINK_PIN;
398 hal_gpio_init_out(g_led_pin, 1);
399
400 if (img_mgmt_read_info(0, &ver, NULL, NULL) == 0) {
401 rc = img_mgmt_ver_str(&ver, ver_str);
402 assert(rc == 0);
403 console_printf("\nOMP_SVR %s\n", ver_str);
404 } else {
405 console_printf("\nOMP_SVR\n");
406 }
407
408 while (1) {
409 t = os_sched_get_current_task();
410 assert(t->t_func == task1_handler);
411
412 ++g_task1_loops;
413
414 /* Wait one second */
415 os_time_delay(OS_TICKS_PER_SEC);
416
417 /* Toggle the LED */
418 prev_pin_state = hal_gpio_read(g_led_pin);
419 curr_pin_state = hal_gpio_toggle(g_led_pin);
420 MODLOG_DFLT(INFO, "GPIO %d: %u to %u\n", g_led_pin,
421 prev_pin_state, curr_pin_state);
422 STATS_INC(g_stats_gpio_toggle, toggles);
423
424 /* Release semaphore to task 2 */
425 os_sem_release(&g_test_sem);
426 }
427 }
428
429 void
task2_handler(void * arg)430 task2_handler(void *arg)
431 {
432 struct os_task *t;
433
434 while (1) {
435 /* just for debug; task 2 should be the running task */
436 t = os_sched_get_current_task();
437 assert(t->t_func == task2_handler);
438
439 /* Increment # of times we went through task loop */
440 ++g_task2_loops;
441
442 /* Wait for semaphore from ISR */
443 os_sem_pend(&g_test_sem, OS_TIMEOUT_NEVER);
444 }
445 }
446
447 /*
448 * OIC platform/resource registration.
449 */
450 static void
omgr_app_init(void)451 omgr_app_init(void)
452 {
453 oc_init_platform("MyNewt", NULL, NULL);
454 }
455
456 static const oc_handler_t omgr_oc_handler = {
457 .init = omgr_app_init,
458 };
459
460 /**
461 * init_tasks
462 *
463 * Called by main.c after sysinit(). This function performs initializations
464 * that are required before tasks are running.
465 *
466 * @return int 0 success; error otherwise.
467 */
468 static void
init_tasks(void)469 init_tasks(void)
470 {
471 os_stack_t *pstack;
472 /* Initialize global test semaphore */
473 os_sem_init(&g_test_sem, 0);
474
475 pstack = malloc(sizeof(os_stack_t)*TASK1_STACK_SIZE);
476 assert(pstack);
477
478 os_task_init(&task1, "task1", task1_handler, NULL,
479 TASK1_PRIO, OS_WAIT_FOREVER, pstack, TASK1_STACK_SIZE);
480
481 pstack = malloc(sizeof(os_stack_t)*TASK2_STACK_SIZE);
482 assert(pstack);
483
484 os_task_init(&task2, "task2", task2_handler, NULL,
485 TASK2_PRIO, OS_WAIT_FOREVER, pstack, TASK2_STACK_SIZE);
486
487 oc_main_init((oc_handler_t *)&omgr_oc_handler);
488 }
489
490 /**
491 * main
492 *
493 * The main task for the project. This function initializes the packages, calls
494 * init_tasks to initialize additional tasks (and possibly other objects),
495 * then starts serving events from default event queue.
496 *
497 * @return int NOTE: this function should never return!
498 */
499 int
main(int argc,char ** argv)500 main(int argc, char **argv)
501 {
502 int rc;
503
504 #ifdef ARCH_sim
505 mcu_sim_parse_args(argc, argv);
506 #endif
507 sysinit();
508
509 #ifndef ARCH_sim
510 oc_ble_coap_gatt_srv_init();
511
512 /* Initialize the NimBLE host configuration. */
513 ble_hs_cfg.reset_cb = omp_svr_on_reset;
514 ble_hs_cfg.sync_cb = omp_svr_on_sync;
515 ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
516 ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
517
518 /* Set the default device name. */
519 rc = ble_svc_gap_device_name_set("mynewt-omp-svr");
520 assert(rc == 0);
521 #endif
522
523 rc = conf_register(&test_conf_handler);
524 assert(rc == 0);
525
526 stats_init(STATS_HDR(g_stats_gpio_toggle),
527 STATS_SIZE_INIT_PARMS(g_stats_gpio_toggle, STATS_SIZE_32),
528 STATS_NAME_INIT_PARMS(gpio_stats));
529
530 stats_register("gpio_toggle", STATS_HDR(g_stats_gpio_toggle));
531
532 reboot_start(hal_reset_cause());
533
534 #if MYNEWT_VAL(SPLIT_LOADER)
535 {
536 void *entry;
537 rc = split_app_go(&entry, true);
538 if(rc == 0) {
539 hal_system_start(entry);
540 }
541 }
542 #endif
543
544 init_tasks();
545
546 while (1) {
547 os_eventq_run(os_eventq_dflt_get());
548 }
549 /* Never returns */
550
551 return rc;
552 }
553