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