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);
+}