You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/01/19 02:35:21 UTC
[3/3] incubator-mynewt-larva git commit: bleshell project for ble
testing.
bleshell project for ble testing.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/caecf1da
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/caecf1da
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/caecf1da
Branch: refs/heads/master
Commit: caecf1dab34428f3342bfe9ad4d91b0215e2ddc6
Parents: 4fdf587
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Jan 18 17:28:28 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Mon Jan 18 17:33:29 2016 -0800
----------------------------------------------------------------------
project/bleshell/bleshell.yml | 8 +
project/bleshell/src/bleshell_priv.h | 57 +++++
project/bleshell/src/cmd.c | 352 +++++++++++++++++++++++++++
project/bleshell/src/main.c | 392 ++++++++++++++++++++++++++++++
project/bleshell/src/parse.c | 211 ++++++++++++++++
project/bleshell/src/periph.c | 123 ++++++++++
6 files changed, 1143 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/bleshell.yml
----------------------------------------------------------------------
diff --git a/project/bleshell/bleshell.yml b/project/bleshell/bleshell.yml
new file mode 100644
index 0000000..300c6a0
--- /dev/null
+++ b/project/bleshell/bleshell.yml
@@ -0,0 +1,8 @@
+project.name: bleshell
+project.eggs:
+ - libs/os
+ - net/nimble/controller
+ - net/nimble/host
+ - libs/console/full
+ - libs/shell
+ - libs/baselibc
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/src/bleshell_priv.h
----------------------------------------------------------------------
diff --git a/project/bleshell/src/bleshell_priv.h b/project/bleshell/src/bleshell_priv.h
new file mode 100644
index 0000000..942f3d8
--- /dev/null
+++ b/project/bleshell/src/bleshell_priv.h
@@ -0,0 +1,57 @@
+#ifndef H_BLESHELL_PRIV_
+#define H_BLESHELL_PRIV_
+
+#include <inttypes.h>
+#include "os/queue.h"
+
+#include "host/ble_gatt.h"
+
+#define BLESHELL_MAX_CONNS 8
+
+typedef int cmd_fn(int argc, char **argv);
+struct cmd_entry {
+ char *name;
+ cmd_fn *cb;
+};
+
+struct kv_pair {
+ char *key;
+ int val;
+};
+
+struct bleshell_svc {
+ STAILQ_ENTRY(bleshell_svc) next;
+ struct ble_gatt_service svc;
+};
+
+STAILQ_HEAD(bleshell_svc_list, bleshell_svc);
+
+struct bleshell_conn {
+ uint16_t handle;
+ uint8_t addr_type;
+ uint8_t addr[6];
+
+ struct bleshell_svc_list svcs;
+};
+
+extern struct bleshell_conn bleshell_conns[BLESHELL_MAX_CONNS];
+extern int bleshell_num_conns;
+
+void print_addr(void *addr);
+void print_uuid(void *uuid128);
+struct cmd_entry *parse_cmd_find(struct cmd_entry *cmds, char *name);
+struct kv_pair *parse_kv_find(struct kv_pair *kvs, char *name);
+char *parse_arg_find(char *key);
+int parse_arg_int(char *name);
+int parse_arg_kv(char *name, struct kv_pair *kvs);
+int parse_arg_mac(char *name, uint8_t *dst);
+int parse_err_too_few_args(char *cmd_name);
+int parse_arg_all(int argc, char **argv);
+int cmd_init(void);
+void periph_init(void);
+int bleshell_disc_svcs(uint16_t conn_handle);
+int bleshell_adv_start(int disc, int conn, uint8_t *peer_addr, int addr_type);
+int bleshell_adv_stop(void);
+int bleshell_conn_initiate(int addr_type, uint8_t *peer_addr);
+
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/src/cmd.c
----------------------------------------------------------------------
diff --git a/project/bleshell/src/cmd.c b/project/bleshell/src/cmd.c
new file mode 100644
index 0000000..e187d13
--- /dev/null
+++ b/project/bleshell/src/cmd.c
@@ -0,0 +1,352 @@
+#include <errno.h>
+#include <string.h>
+#include "console/console.h"
+#include "shell/shell.h"
+
+#include "nimble/ble.h"
+#include "nimble/hci_common.h"
+#include "host/ble_gap.h"
+
+#include "bleshell_priv.h"
+
+static struct shell_cmd cmd_b;
+
+/*****************************************************************************
+ * $misc *
+ *****************************************************************************/
+
+static int
+cmd_exec(struct cmd_entry *cmds, int argc, char **argv)
+{
+ struct cmd_entry *cmd;
+ int rc;
+
+ if (argc <= 1) {
+ return parse_err_too_few_args(argv[0]);
+ }
+
+ cmd = parse_cmd_find(cmds, argv[1]);
+ if (cmd == NULL) {
+ console_printf("Error: unknown %s command: %s\n", argv[0], argv[1]);
+ return -1;
+ }
+
+ rc = cmd->cb(argc - 1, argv + 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * $advertise *
+ *****************************************************************************/
+
+static struct kv_pair cmd_adv_conn_modes[] = {
+ { "non", BLE_GAP_CONN_MODE_NON },
+ { "und", BLE_GAP_CONN_MODE_UND },
+ { "dir", BLE_GAP_CONN_MODE_DIR },
+ { NULL }
+};
+
+static struct kv_pair cmd_adv_disc_modes[] = {
+ { "non", BLE_GAP_DISC_MODE_NON },
+ { "ltd", BLE_GAP_DISC_MODE_LTD },
+ { "gen", BLE_GAP_DISC_MODE_GEN },
+ { NULL }
+};
+
+static struct kv_pair cmd_adv_addr_types[] = {
+ { "public", BLE_ADDR_TYPE_PUBLIC },
+ { "random", BLE_ADDR_TYPE_RANDOM },
+ { NULL }
+};
+
+static int
+cmd_adv(int argc, char **argv)
+{
+ uint8_t peer_addr[6];
+ int addr_type;
+ int conn;
+ int disc;
+ int rc;
+
+ if (argc > 1 && strcmp(argv[1], "stop") == 0) {
+ rc = bleshell_adv_stop();
+ if (rc != 0) {
+ console_printf("advertise stop fail: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+ }
+
+ conn = parse_arg_kv("conn", cmd_adv_conn_modes);
+ if (conn == -1) {
+ console_printf("invalid 'conn' parameter\n");
+ return -1;
+ }
+
+
+ disc = parse_arg_kv("disc", cmd_adv_disc_modes);
+ if (disc == -1) {
+ console_printf("missing 'disc' parameter\n");
+ return -1;
+ }
+
+ if (conn == BLE_GAP_CONN_MODE_DIR) {
+ addr_type = parse_arg_kv("addr_type", cmd_adv_addr_types);
+ if (addr_type == -1) {
+ return -1;
+ }
+
+ rc = parse_arg_mac("addr", peer_addr);
+ if (rc != 0) {
+ return rc;
+ }
+ } else {
+ addr_type = 0;
+ memset(peer_addr, 0, sizeof peer_addr);
+ }
+
+ rc = bleshell_adv_start(disc, conn, peer_addr, addr_type);
+ if (rc != 0) {
+ console_printf("advertise fail: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * $connect *
+ *****************************************************************************/
+
+static struct kv_pair cmd_conn_addr_types[] = {
+ { "public", BLE_HCI_CONN_PEER_ADDR_PUBLIC },
+ { "random", BLE_HCI_CONN_PEER_ADDR_RANDOM },
+ { "public_ident", BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT },
+ { "random_ident", BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT },
+ { "wl", BLE_GAP_ADDR_TYPE_WL },
+ { NULL }
+};
+
+static int
+cmd_conn(int argc, char **argv)
+{
+ uint8_t peer_addr[6];
+ int addr_type;
+ int rc;
+
+ addr_type = parse_arg_kv("addr_type", cmd_conn_addr_types);
+ if (addr_type == -1) {
+ return -1;
+ }
+
+ if (addr_type != BLE_GAP_ADDR_TYPE_WL) {
+ rc = parse_arg_mac("addr", peer_addr);
+ if (rc != 0) {
+ return rc;
+ }
+ } else {
+ memset(peer_addr, 0, sizeof peer_addr);
+ }
+
+ rc = bleshell_conn_initiate(addr_type, peer_addr);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * $discover *
+ *****************************************************************************/
+
+static int
+cmd_disc_svc(int argc, char **argv)
+{
+ int conn_handle;
+ int rc;
+
+ conn_handle = parse_arg_int("conn");
+ if (conn_handle == -1) {
+ return -1;
+ }
+
+ rc = bleshell_disc_svcs(conn_handle);
+ if (rc != 0) {
+ console_printf("error discovering services; rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static struct cmd_entry cmd_disc_entries[] = {
+ { "svc", cmd_disc_svc },
+ { NULL, NULL }
+};
+
+static int
+cmd_disc(int argc, char **argv)
+{
+ int rc;
+
+ rc = cmd_exec(cmd_disc_entries, argc, argv);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * $show *
+ *****************************************************************************/
+
+static int
+cmd_show_addr(int argc, char **argv)
+{
+ console_printf("myaddr=");
+ print_addr(g_dev_addr);
+ console_printf("\n");
+
+ return 0;
+}
+
+static int
+cmd_show_conn(int argc, char **argv)
+{
+ struct bleshell_conn *conn;
+ int i;
+
+ for (i = 0; i < bleshell_num_conns; i++) {
+ conn = bleshell_conns + i;
+
+ console_printf("handle=%d addr=", conn->handle);
+ print_addr(conn->addr);
+ console_printf(" addr_type=%d\n", conn->addr_type);
+ }
+
+ return 0;
+}
+
+static int
+cmd_show_svc(int argc, char **argv)
+{
+ struct bleshell_conn *conn;
+ struct bleshell_svc *svc;
+ int i;
+
+ for (i = 0; i < bleshell_num_conns; i++) {
+ conn = bleshell_conns + i;
+
+ console_printf("CONNECTION: handle=%d addr=", conn->handle);
+ print_addr(conn->addr);
+ console_printf("\n");
+
+ STAILQ_FOREACH(svc, &conn->svcs, next) {
+ console_printf(" start=%d end=%d uuid=", svc->svc.start_handle,
+ svc->svc.end_handle);
+ print_uuid(svc->svc.uuid128);
+ console_printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+static struct cmd_entry cmd_show_entries[] = {
+ { "addr", cmd_show_addr },
+ { "conn", cmd_show_conn },
+ { "svc", cmd_show_svc },
+ { NULL, NULL }
+};
+
+static int
+cmd_show(int argc, char **argv)
+{
+ int rc;
+
+ rc = cmd_exec(cmd_show_entries, argc, argv);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * $set *
+ *****************************************************************************/
+
+static int
+cmd_set(int argc, char **argv)
+{
+ uint8_t addr[6];
+ int good;
+ int rc;
+
+ good = 0;
+
+ rc = parse_arg_mac("addr", addr);
+ if (rc == 0) {
+ good = 1;
+ memcpy(g_dev_addr, addr, 6);
+ }
+
+ if (!good) {
+ console_printf("Error: no valid settings specified\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct cmd_entry cmd_b_entries[] = {
+ { "adv", cmd_adv },
+ { "conn", cmd_conn },
+ { "disc", cmd_disc },
+ { "show", cmd_show },
+ { "set", cmd_set },
+ { NULL, NULL }
+};
+
+/*****************************************************************************
+ * $init *
+ *****************************************************************************/
+
+static int
+cmd_b_exec(int argc, char **argv)
+{
+ int rc;
+
+ rc = parse_arg_all(argc - 1, argv + 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = cmd_exec(cmd_b_entries, argc, argv);
+ if (rc != 0) {
+ console_printf("error\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+cmd_init(void)
+{
+ int rc;
+
+ rc = shell_cmd_register(&cmd_b, "b", cmd_b_exec);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/src/main.c
----------------------------------------------------------------------
diff --git a/project/bleshell/src/main.c b/project/bleshell/src/main.c
new file mode 100755
index 0000000..4a6e0fb
--- /dev/null
+++ b/project/bleshell/src/main.c
@@ -0,0 +1,392 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "os/os.h"
+#include "bsp/bsp.h"
+#include "hal/hal_gpio.h"
+#include "hal/hal_cputime.h"
+#include "console/console.h"
+#include "shell/shell.h"
+#include "bleshell_priv.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "host/host_hci.h"
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "host/ble_att.h"
+#include "host/ble_gap.h"
+#include "host/ble_gatt.h"
+#include "controller/ble_ll.h"
+
+/* Task 1 */
+#define HOST_TASK_PRIO (1)
+
+#define SHELL_TASK_PRIO (3)
+#define SHELL_TASK_STACK_SIZE (OS_STACK_ALIGN(256))
+os_stack_t shell_stack[SHELL_TASK_STACK_SIZE];
+
+/* For LED toggling */
+int g_led_pin;
+
+/* Our global device address (public) */
+uint8_t g_dev_addr[BLE_DEV_ADDR_LEN];
+
+/* Our random address (in case we need it) */
+uint8_t g_random_addr[BLE_DEV_ADDR_LEN];
+
+/* A buffer for host advertising data */
+uint8_t g_host_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
+uint8_t g_host_adv_len;
+
+static uint8_t bleshell_addr[6] = {0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a};
+
+/* Create a mbuf pool of BLE mbufs */
+#define MBUF_NUM_MBUFS (8)
+#define MBUF_BUF_SIZE (256 + sizeof(struct hci_data_hdr))
+#define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
+
+#define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE)
+
+struct os_mbuf_pool g_mbuf_pool;
+struct os_mempool g_mbuf_mempool;
+os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
+
+/* BLESHELL variables */
+#define BLESHELL_STACK_SIZE (256)
+#define BLESHELL_TASK_PRIO (HOST_TASK_PRIO + 1)
+
+#define BLESHELL_MAX_SVCS 16
+
+uint32_t g_next_os_time;
+int g_bleshell_state;
+struct os_eventq g_bleshell_evq;
+struct os_task bleshell_task;
+os_stack_t bleshell_stack[BLESHELL_STACK_SIZE];
+
+struct bleshell_conn ble_shell_conns[BLESHELL_MAX_CONNS];
+int bleshell_num_conns;
+
+void
+bletest_inc_adv_pkt_num(void) { }
+
+struct bleshell_conn bleshell_conns[BLESHELL_MAX_CONNS];
+int bleshell_num_conns;
+
+static void *bleshell_svc_mem;
+static struct os_mempool bleshell_svc_pool;
+
+static int
+bleshell_conn_find_idx(uint16_t handle)
+{
+ int i;
+
+ for (i = 0; i < bleshell_num_conns; i++) {
+ if (bleshell_conns[i].handle == handle) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static struct bleshell_conn *
+bleshell_conn_find(uint16_t handle)
+{
+ int idx;
+
+ idx = bleshell_conn_find_idx(handle);
+ if (idx == -1) {
+ return NULL;
+ } else {
+ return bleshell_conns + idx;
+ }
+}
+
+static struct bleshell_conn *
+bleshell_conn_add(struct ble_gap_conn_desc *desc)
+{
+ struct bleshell_conn *conn;
+
+ assert(bleshell_num_conns < BLESHELL_MAX_CONNS);
+
+ conn = bleshell_conns + bleshell_num_conns;
+ bleshell_num_conns++;
+
+ conn->handle = desc->conn_handle;
+ conn->addr_type = desc->peer_addr_type;
+ memcpy(conn->addr, desc->peer_addr, 6);
+ STAILQ_INIT(&conn->svcs);
+
+ return conn;
+}
+
+static void
+bleshell_conn_delete_idx(int idx)
+{
+ struct bleshell_conn *conn;
+ struct bleshell_svc *svc;
+ int i;
+
+ assert(idx >= 0 && idx < bleshell_num_conns);
+
+ conn = bleshell_conns + idx;
+ while ((svc = STAILQ_FIRST(&conn->svcs)) != NULL) {
+ STAILQ_REMOVE_HEAD(&conn->svcs, next);
+ os_memblock_put(&bleshell_svc_pool, svc);
+ }
+
+ bleshell_num_conns--;
+ for (i = idx; i < bleshell_num_conns; i++) {
+ bleshell_conns[i - 1] = bleshell_conns[i];
+ }
+}
+
+static struct bleshell_svc *
+bleshell_svc_add(uint16_t conn_handle, struct ble_gatt_service *gatt_svc)
+{
+ struct bleshell_conn *conn;
+ struct bleshell_svc *svc;
+
+ conn = bleshell_conn_find(conn_handle);
+ if (conn == NULL) {
+ console_printf("RECEIVED SERVICE FOR UNKNOWN CONNECTION; HANDLE=%d\n",
+ conn_handle);
+ return NULL;
+ }
+
+ svc = os_memblock_get(&bleshell_svc_pool);
+ if (svc == NULL) {
+ console_printf("OOM WHILE DISCOVERING SERVICE\n");
+ return NULL;
+ }
+
+ svc->svc = *gatt_svc;
+ STAILQ_INSERT_TAIL(&conn->svcs, svc, next);
+
+ return svc;
+}
+
+static int
+bleshell_on_disc_s(uint16_t conn_handle, struct ble_gatt_error *error,
+ struct ble_gatt_service *service, void *arg)
+{
+ if (error != NULL) {
+ console_printf("ERROR DISCOVERING SERVICE: conn_handle=%d status=%d "
+ "att_handle=%d\n", conn_handle, error->status,
+ error->att_handle);
+ } else if (service != NULL) {
+ bleshell_svc_add(conn_handle, service);
+ } else {
+ /* Service discovery complete. */
+ }
+
+ return 0;
+}
+
+static void
+bleshell_on_connect(int event, int status, struct ble_gap_conn_desc *desc,
+ void *arg)
+{
+ int conn_idx;
+
+ switch (event) {
+ case BLE_GAP_EVENT_CONN:
+ console_printf("connection complete; handle=%d status=%d "
+ "peer_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ desc->conn_handle, status,
+ desc->peer_addr[0], desc->peer_addr[1],
+ desc->peer_addr[2], desc->peer_addr[3],
+ desc->peer_addr[4], desc->peer_addr[5]);
+
+ if (status == 0) {
+ bleshell_conn_add(desc);
+ } else {
+ conn_idx = bleshell_conn_find_idx(desc->conn_handle);
+ if (conn_idx == -1) {
+ console_printf("UNKNOWN CONNECTION\n");
+ } else {
+ bleshell_conn_delete_idx(conn_idx);
+ }
+ }
+
+ break;
+ }
+}
+
+int
+bleshell_disc_svcs(uint16_t conn_handle)
+{
+ int rc;
+
+ rc = ble_gattc_disc_all_svcs(conn_handle, bleshell_on_disc_s, NULL);
+ return rc;
+}
+
+int
+bleshell_adv_stop(void)
+{
+ int rc;
+
+ rc = ble_gap_conn_adv_stop();
+ return rc;
+}
+
+int
+bleshell_adv_start(int disc, int conn, uint8_t *peer_addr, int addr_type)
+{
+ int rc;
+
+ rc = ble_gap_conn_adv_start(disc, conn, peer_addr, addr_type,
+ bleshell_on_connect, NULL);
+ return rc;
+}
+
+int
+bleshell_conn_initiate(int addr_type, uint8_t *peer_addr)
+{
+ int rc;
+
+ rc = ble_gap_conn_initiate(addr_type, peer_addr, bleshell_on_connect,
+ NULL);
+ return rc;
+}
+
+/**
+ * BLE test task
+ *
+ * @param arg
+ */
+static void
+bleshell_task_handler(void *arg)
+{
+ struct os_event *ev;
+ struct os_callout_func *cf;
+
+ periph_init();
+
+ /* Initialize eventq */
+ os_eventq_init(&g_bleshell_evq);
+
+ /* Init bleshell variables */
+ g_bleshell_state = 0;
+ g_next_os_time = os_time_get();
+
+ while (1) {
+ ev = os_eventq_get(&g_bleshell_evq);
+ switch (ev->ev_type) {
+ case OS_EVENT_T_TIMER:
+ cf = (struct os_callout_func *)ev;
+ assert(cf->cf_func);
+ cf->cf_func(cf->cf_arg);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+/**
+ * main
+ *
+ * The main function for the project. This function initializes the os, calls
+ * init_tasks to initialize tasks (and possibly other objects), then starts the
+ * OS. We should not return from os start.
+ *
+ * @return int NOTE: this function should never return!
+ */
+int
+main(void)
+{
+ int i;
+ int rc;
+ uint32_t seed;
+
+ /* Initialize OS */
+ os_init();
+
+ /* Set cputime to count at 1 usec increments */
+ rc = cputime_init(1000000);
+ assert(rc == 0);
+
+ rc = os_mempool_init(&g_mbuf_mempool, MBUF_NUM_MBUFS,
+ MBUF_MEMBLOCK_SIZE, &g_mbuf_buffer[0], "mbuf_pool");
+
+ rc = os_mbuf_pool_init(&g_mbuf_pool, &g_mbuf_mempool, MBUF_MEMBLOCK_SIZE,
+ MBUF_NUM_MBUFS);
+ assert(rc == 0);
+
+ /* Dummy device address */
+ memcpy(g_dev_addr, bleshell_addr, 6);
+
+ /*
+ * Seed random number generator with least significant bytes of device
+ * address.
+ */
+ seed = 0;
+ for (i = 0; i < 4; ++i) {
+ seed |= g_dev_addr[i];
+ seed <<= 8;
+ }
+ srand(seed);
+
+ /* Set the led pin as an output */
+ g_led_pin = LED_BLINK_PIN;
+ gpio_init_out(g_led_pin, 1);
+
+ bleshell_svc_mem = malloc(
+ OS_MEMPOOL_BYTES(BLESHELL_MAX_SVCS, sizeof (struct bleshell_svc)));
+ assert(bleshell_svc_mem != NULL);
+
+ rc = os_mempool_init(&bleshell_svc_pool, BLESHELL_MAX_SVCS,
+ sizeof (struct bleshell_svc), bleshell_svc_mem,
+ "bleshell_svc_pool");
+ assert(rc == 0);
+
+ os_task_init(&bleshell_task, "bleshell", bleshell_task_handler,
+ NULL, BLESHELL_TASK_PRIO, OS_WAIT_FOREVER,
+ bleshell_stack, BLESHELL_STACK_SIZE);
+
+ /* Initialize host HCI */
+ rc = ble_hs_init(HOST_TASK_PRIO);
+ assert(rc == 0);
+
+ /* Initialize the BLE LL */
+ ble_ll_init();
+
+ rc = shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE);
+ assert(rc == 0);
+
+ /* Init the console */
+ rc = console_init(shell_console_rx_cb);
+ assert(rc == 0);
+
+ rc = cmd_init();
+ assert(rc == 0);
+
+ /* Start the OS */
+ os_start();
+
+ /* os start should never return. If it does, this should be an error */
+ assert(0);
+
+ return 0;
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/src/parse.c
----------------------------------------------------------------------
diff --git a/project/bleshell/src/parse.c b/project/bleshell/src/parse.c
new file mode 100644
index 0000000..04afb83
--- /dev/null
+++ b/project/bleshell/src/parse.c
@@ -0,0 +1,211 @@
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "console/console.h"
+#include "host/ble_uuid.h"
+#include "bleshell_priv.h"
+
+#define CMD_MAX_ARG_LEN 32
+#define CMD_MAX_ARGS 16
+
+static char cmd_args[CMD_MAX_ARGS][2][CMD_MAX_ARG_LEN];
+static int cmd_num_args;
+
+void
+print_addr(void *addr)
+{
+ uint8_t *u8p;
+
+ u8p = addr;
+ console_printf("%02x:%02x:%02x:%02x:%02x:%02x",
+ u8p[0], u8p[1], u8p[2], u8p[3], u8p[4], u8p[5]);
+}
+
+void
+print_uuid(void *uuid128)
+{
+ uint16_t uuid16;
+ uint8_t *u8p;
+
+ uuid16 = ble_uuid_128_to_16(uuid128);
+ if (uuid16 != 0) {
+ console_printf("0x%04x", uuid16);
+ return;
+ }
+
+ u8p = uuid128;
+
+ /* 00001101-0000-1000-8000-00805f9b34fb */
+ console_printf("%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13], u8p[12]);
+ console_printf("%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]);
+ console_printf("%02x%02x%02x%02x%02x%02x%02x%02x",
+ u8p[7], u8p[6], u8p[5], u8p[4],
+ u8p[3], u8p[2], u8p[1], u8p[0]);
+}
+
+int
+parse_err_too_few_args(char *cmd_name)
+{
+ console_printf("Error: too few arguments for command \"%s\"\n", cmd_name);
+ return -1;
+}
+
+struct cmd_entry *
+parse_cmd_find(struct cmd_entry *cmds, char *name)
+{
+ struct cmd_entry *cmd;
+ int i;
+
+ for (i = 0; cmds[i].name != NULL; i++) {
+ cmd = cmds + i;
+ if (strcmp(name, cmd->name) == 0) {
+ return cmd;
+ }
+ }
+
+ return NULL;
+}
+
+struct kv_pair *
+parse_kv_find(struct kv_pair *kvs, char *name)
+{
+ struct kv_pair *kv;
+ int i;
+
+ for (i = 0; kvs[i].key != NULL; i++) {
+ kv = kvs + i;
+ if (strcmp(name, kv->key) == 0) {
+ return kv;
+ }
+ }
+
+ return NULL;
+}
+
+char *
+parse_arg_find(char *key)
+{
+ int i;
+
+ for (i = 0; i < cmd_num_args; i++) {
+ if (strcmp(cmd_args[i][0], key) == 0) {
+ return cmd_args[i][1];
+ }
+ }
+
+ return NULL;
+}
+
+int
+parse_arg_int(char *name)
+{
+ char *endptr;
+ char *sval;
+ long lval;
+
+ sval = parse_arg_find(name);
+ if (sval == NULL) {
+ return -1;
+ }
+
+ lval = strtol(sval, &endptr, 0);
+ if (sval[0] != '\0' && *endptr == '\0' &&
+ lval >= INT_MIN && lval <= INT_MAX) {
+
+ return lval;
+ }
+
+ return -1;
+}
+
+int
+parse_arg_kv(char *name, struct kv_pair *kvs)
+{
+ struct kv_pair *kv;
+ char *sval;
+
+ sval = parse_arg_find(name);
+ if (sval == NULL) {
+ return -1;
+ }
+
+ kv = parse_kv_find(kvs, sval);
+ if (kv == NULL) {
+ return -1;
+ }
+
+ return kv->val;
+}
+
+int
+parse_arg_mac(char *name, uint8_t *dst)
+{
+ unsigned long ul;
+ char *endptr;
+ char *token;
+ char *sval;
+ int i;
+
+ sval = parse_arg_find(name);
+ if (sval == NULL) {
+ return -1;
+ }
+
+ token = strtok(sval, ":");
+ for (i = 0; i < 6; i++) {
+ if (token == NULL) {
+ return -1;
+ }
+
+ ul = strtoul(token, &endptr, 16);
+ if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) {
+ return -1;
+ }
+
+ dst[i] = ul;
+
+ token = strtok(NULL, ":");
+ }
+
+ if (token != NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+parse_arg_all(int argc, char **argv)
+{
+ char *key;
+ char *val;
+ int i;
+
+ cmd_num_args = 0;
+
+ for (i = 0; i < argc; i++) {
+ key = strtok(argv[i], "=");
+ val = strtok(NULL, "=");
+
+ if (key != NULL && val != NULL) {
+ if (strlen(key) == 0 || strlen(key) >= CMD_MAX_ARG_LEN ||
+ strlen(val) >= CMD_MAX_ARG_LEN) {
+
+ console_printf("Error: invalid argument: %s\n", argv[i]);
+ return -1;
+ }
+
+ if (cmd_num_args >= CMD_MAX_ARGS) {
+ console_printf("Error: too many arguments");
+ return -1;
+ }
+
+ strcpy(cmd_args[cmd_num_args][0], key);
+ strcpy(cmd_args[cmd_num_args][1], val);
+ cmd_num_args++;
+ }
+ }
+
+ return 0;
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/caecf1da/project/bleshell/src/periph.c
----------------------------------------------------------------------
diff --git a/project/bleshell/src/periph.c b/project/bleshell/src/periph.c
new file mode 100644
index 0000000..8146171
--- /dev/null
+++ b/project/bleshell/src/periph.c
@@ -0,0 +1,123 @@
+#include <assert.h>
+#include <string.h>
+#include "console/console.h"
+#include "host/ble_hs.h"
+
+#define PERIPH_SVC1_UUID 0x1234
+#define PERIPH_SVC2_UUID 0x5678
+#define PERIPH_CHR1_UUID 0x1111
+#define PERIPH_CHR2_UUID 0x1112
+#define PERIPH_CHR3_UUID 0x5555
+
+static int
+periph_gatt_cb(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+ union ble_gatt_access_ctxt *ctxt, void *arg);
+
+static const struct ble_gatt_svc_def periph_svcs[] = { {
+ /*** Service 0x1234. */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid128 = BLE_UUID16(PERIPH_SVC1_UUID),
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ /*** Characteristic 0x1111. */
+ .uuid128 = BLE_UUID16(PERIPH_CHR1_UUID),
+ .access_cb = periph_gatt_cb,
+ .flags = 0,
+ }, {
+ /*** Characteristic 0x1112. */
+ .uuid128 = BLE_UUID16(PERIPH_CHR2_UUID),
+ .access_cb = periph_gatt_cb,
+ .flags = 0,
+ }, {
+ .uuid128 = NULL, /* No more characteristics in this service. */
+ } },
+}, {
+ /*** Service 0x5678. */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid128 = BLE_UUID16(PERIPH_SVC2_UUID),
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ /*** Characteristic 0x5555. */
+ .uuid128 = BLE_UUID16(PERIPH_CHR3_UUID),
+ .access_cb = periph_gatt_cb,
+ .flags = 0,
+ }, {
+ .uuid128 = NULL, /* No more characteristics in this service. */
+ } },
+}, {
+ .type = BLE_GATT_SVC_TYPE_END, /* No more services. */
+}, };
+
+static int
+periph_gatt_cb(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
+ union ble_gatt_access_ctxt *ctxt, void *arg)
+{
+ static uint8_t buf[128];
+ uint16_t uuid16;
+
+ assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+
+ uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128);
+ switch (uuid16) {
+ case PERIPH_CHR1_UUID:
+ console_printf("reading characteristic1 value\n");
+ memcpy(buf, "char1", 5);
+ ctxt->chr_access.len = 5;
+ break;
+
+ case PERIPH_CHR2_UUID:
+ console_printf("reading characteristic2 value\n");
+ memcpy(buf, "char2", 5);
+ ctxt->chr_access.len = 5;
+ break;
+
+ case PERIPH_CHR3_UUID:
+ console_printf("reading characteristic3 value\n");
+ memcpy(buf, "char3", 5);
+ ctxt->chr_access.len = 5;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ ctxt->chr_access.data = buf;
+
+ return 0;
+}
+
+static void
+periph_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg)
+{
+ uint16_t uuid16;
+
+ switch (op) {
+ case BLE_GATT_REGISTER_OP_SVC:
+ uuid16 = ble_uuid_128_to_16(ctxt->svc_reg.svc->uuid128);
+ assert(uuid16 != 0);
+ console_printf("registered service 0x%04x with handle=%d\n",
+ uuid16, ctxt->svc_reg.handle);
+ break;
+
+ case BLE_GATT_REGISTER_OP_CHR:
+ uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128);
+ assert(uuid16 != 0);
+ console_printf("registering characteristic 0x%04x with def_handle=%d "
+ "val_handle=%d\n",
+ uuid16, ctxt->chr_reg.def_handle,
+ ctxt->chr_reg.val_handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+void
+periph_init(void)
+{
+ int rc;
+
+ rc = ble_gatts_register_svcs(periph_svcs, periph_register_cb, NULL);
+ assert(rc == 0);
+}