/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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>

/* BLE */
#include "nimble/ble.h"
#include "nimble/ble_hci_trans.h"
#include "nimble/hci_common.h"
#include "host/ble_hs.h"

#include "nimble/nimble_npl.h"
#include "nimble/npl_shell.h"

/* XXX: An app should not include private headers from a library.  The bletest
 * app uses some of nimble's internal details for logging.
 */
#include "ble_hs_priv.h"
#include "bletest_priv.h"

#include <rtthread.h>

#define BLETEST_TASK_PRIO               5

/* For LED toggling */
int g_led_pin;

/* 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 _g_dev_addr[BLE_DEV_ADDR_LEN];

/* Some application configurations */
#define BLETEST_ROLE_NONE               (0)
#define BLETEST_ROLE_ADVERTISER         (1)
#define BLETEST_ROLE_SCANNER            (2)
#define BLETEST_ROLE_INITIATOR          (3)

#define MYNEWT_VAL_BLETEST_ROLE BLETEST_ROLE_ADVERTISER

#if MYNEWT_VAL(BLETEST_ROLE) == BLETEST_ROLE_ADVERTISER
#define BLETEST_CFG_ROLE                BLETEST_ROLE_ADVERTISER
#endif
#if MYNEWT_VAL(BLETEST_ROLE) == BLETEST_ROLE_SCANNER
#define BLETEST_CFG_ROLE                BLETEST_ROLE_SCANNER
#endif
#if MYNEWT_VAL(BLETEST_ROLE) == BLETEST_ROLE_INITIATOR
#define BLETEST_CFG_ROLE                BLETEST_ROLE_INITIATOR
#endif

#ifndef BLETEST_CFG_ROLE
#error "No role defined! Must define a valid role in syscfg.yml in apps/bletest"
#endif

/* Advertiser config */
#define BLETEST_CFG_ADV_OWN_ADDR_TYPE   (BLE_HCI_ADV_OWN_ADDR_PUBLIC)
#define BLETEST_CFG_ADV_PEER_ADDR_TYPE  (BLE_HCI_ADV_PEER_ADDR_PUBLIC)
#define BLETEST_CFG_ADV_ITVL            (60000 / BLE_HCI_ADV_ITVL)
#define BLETEST_CFG_ADV_TYPE            BLE_HCI_ADV_TYPE_ADV_IND
#define BLETEST_CFG_ADV_FILT_POLICY     (BLE_HCI_ADV_FILT_NONE)
#define BLETEST_CFG_ADV_ADDR_RES_EN     (0)

/* Multi-adv config */
/*
 * Number of advertising instances to start up, not including the default
 * instance. The default instance is used to connect. If this number is greater
 * than the number of available advertising instances, we only use the number
 * of available advertising instances (defined by the configuration setting:
 * BLE_MULTI_ADV_INSTANCES.
 */
#define BLETEST_CFG_ADV_TEST_INSTANCES     (8)

struct bletest_multi_adv_interval
{
    uint8_t adv_type;
    /*
     * Note: if own addr type greater than 1, we use own addr field; otherwise
     * we use the set multi random address call to set the random address
     */
    uint8_t adv_own_addr_type;
    uint16_t adv_itvl;
};

/*
 * NOTE: currently, these are all NONCONN_IND. Thus, must be 100 msecs or
 * greater
 */
const struct bletest_multi_adv_interval
bletest_multi_adv_instances[BLETEST_CFG_ADV_TEST_INSTANCES] = {
    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
     (100000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
     BLE_HCI_ADV_OWN_ADDR_RANDOM,
     (110000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
     BLE_HCI_ADV_OWN_ADDR_RANDOM,
     (120000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
     (130000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
     BLE_HCI_ADV_OWN_ADDR_MAX + 1,
     (140000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
     BLE_HCI_ADV_OWN_ADDR_MAX + 1,
     (150000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_NONCONN_IND,
     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
     (160000 / BLE_HCI_ADV_ITVL)},

    {BLE_HCI_ADV_TYPE_ADV_SCAN_IND,
     BLE_HCI_ADV_OWN_ADDR_PUBLIC,
     (170000 / BLE_HCI_ADV_ITVL)}
};

/*
 * Determines if own address contains random address or set through the
 * multi-adv set random address command
 */
#define BLETEST_CFG_MULTI_ADV_RANDOM_OWN    (0)

/* Scan config */
#define BLETEST_CFG_SCAN_ITVL           (700000 / BLE_HCI_SCAN_ITVL)
#define BLETEST_CFG_SCAN_WINDOW         (700000 / BLE_HCI_SCAN_ITVL)
#define BLETEST_CFG_SCAN_TYPE           (BLE_HCI_SCAN_TYPE_PASSIVE)
#define BLETEST_CFG_SCAN_OWN_ADDR_TYPE  (BLE_HCI_ADV_OWN_ADDR_PUBLIC)
#define BLETEST_CFG_SCAN_FILT_POLICY    (BLE_HCI_SCAN_FILT_NO_WL)
#define BLETEST_CFG_FILT_DUP_ADV        (1)

/* Connection config */
#define BLETEST_CFG_CONN_ITVL           (128)  /* in 1.25 msec increments */
#define BLETEST_CFG_SLAVE_LATENCY       (0)
#define BLETEST_CFG_INIT_FILTER_POLICY  (BLE_HCI_CONN_FILT_NO_WL)
#define BLETEST_CFG_CONN_SPVN_TMO       (1000)  /* 10 msec increments */
#define BLETEST_CFG_MIN_CE_LEN          (6)
#define BLETEST_CFG_MAX_CE_LEN          (BLETEST_CFG_CONN_ITVL)
#define BLETEST_CFG_CONN_PEER_ADDR_TYPE (BLE_HCI_CONN_PEER_ADDR_PUBLIC)
#define BLETEST_CFG_CONN_OWN_ADDR_TYPE  (BLE_HCI_ADV_OWN_ADDR_PUBLIC)
#define BLETEST_CFG_CONCURRENT_CONNS    (1)

/* Test packet config */
#define BLETEST_CFG_RAND_PKT_SIZE       (1)
#define BLETEST_CFG_SUGG_DEF_TXOCTETS   (251)
#define BLETEST_CFG_SUGG_DEF_TXTIME     (2000)

/* Test configurations. One of these should be set to 1 */
#if !defined(BLETEST_CONCURRENT_CONN_TEST) && !defined(BLETEST_THROUGHPUT_TEST)
    #define BLETEST_CONCURRENT_CONN_TEST    (1)
#endif

/* BLETEST variables */
#undef BLETEST_ADV_PKT_NUM
#define BLETEST_MAX_PKT_SIZE            (247)
#define BLETEST_PKT_SIZE                (247)
#define BLETEST_STACK_SIZE              (256)
uint32_t g_next_os_time;
int g_bletest_state;
struct ble_npl_eventq g_bletest_evq;
struct ble_npl_callout g_bletest_timer;
//struct ble_npl_task bletest_task;
//bssnz_t os_stack_t bletest_stack[BLETEST_STACK_SIZE];
uint32_t g_bletest_conn_end;
int g_bletest_start_update;
uint32_t g_bletest_conn_upd_time;
uint8_t g_bletest_current_conns;
uint8_t g_bletest_cur_peer_addr[BLE_DEV_ADDR_LEN];
uint8_t g_last_handle_used;
uint8_t g_bletest_led_state;
uint32_t g_bletest_led_rate;
uint32_t g_bletest_next_led_time;
uint16_t g_bletest_handle;
uint16_t g_bletest_completed_pkts;
uint16_t g_bletest_outstanding_pkts;
uint16_t g_bletest_ltk_reply_handle;
uint32_t g_bletest_hw_id[4];
struct hci_create_conn g_cc;

/* --- For LE encryption testing --- */
/* Key: 0x4C68384139F574D836BCF34E9DFB01BF */
const uint8_t g_ble_ll_encrypt_test_key[16] =
{
    0x4c, 0x68, 0x38, 0x41, 0x39, 0xf5, 0x74, 0xd8,
    0x36, 0xbc, 0xf3, 0x4e, 0x9d, 0xfb, 0x01, 0xbf
};

/* Plaint text: 0x0213243546576879acbdcedfe0f10213 */
const uint8_t g_ble_ll_encrypt_test_plain_text[16] =
{
    0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
    0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1, 0x02, 0x13
};

/* Encrypted data: 0x99ad1b5226a37e3e058e3b8e27c2c666 */
const uint8_t g_ble_ll_encrypt_test_encrypted_data[16] =
{
    0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
    0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66
};

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
uint8_t g_bletest_adv_irk[16] = {
    0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
    0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b
};

uint8_t g_bletest_init_irk[16] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
};
#endif

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
/* LTK 0x4C68384139F574D836BCF34E9DFB01BF */
const uint8_t g_bletest_LTK[16] =
{
    0x4C,0x68,0x38,0x41,0x39,0xF5,0x74,0xD8,
    0x36,0xBC,0xF3,0x4E,0x9D,0xFB,0x01,0xBF
};
uint16_t g_bletest_EDIV = 0x2474;
uint64_t g_bletest_RAND = 0xABCDEF1234567890;
uint64_t g_bletest_SKDm = 0xACBDCEDFE0F10213;
uint64_t g_bletest_SKDs = 0x0213243546576879;
uint32_t g_bletest_IVm = 0xBADCAB24;
uint32_t g_bletest_IVs = 0xDEAFBABE;
#endif

#if (BLETEST_THROUGHPUT_TEST == 1)
void
bletest_completed_pkt(uint16_t handle)
{
    os_sr_t sr;

    OS_ENTER_CRITICAL(sr);
    if (handle == g_bletest_handle) {
        ++g_bletest_completed_pkts;
    }
    OS_EXIT_CRITICAL(sr);
}
#endif

#ifdef BLETEST_ADV_PKT_NUM
void
bletest_inc_adv_pkt_num(void)
{
    int rc;
    uint8_t *dptr;
    uint8_t digit;

    if (g_host_adv_len != 0) {
        dptr = &g_host_adv_data[18];
        while (dptr >= &g_host_adv_data[13]) {
            digit = *dptr;
            ++digit;
            if (digit == 58) {
                digit = 48;
                *dptr = digit;
                --dptr;
            } else {
                *dptr = digit;
                break;
            }
        }

        rc = bletest_hci_le_set_adv_data(g_host_adv_data, g_host_adv_len);
        assert(rc == 0);
    }
}
#endif

/**
 * Sets the advertising data to be sent in advertising pdu's which contain
 * advertising data.
 *
 * @param dptr
 * @return uint8_t
 */
uint8_t
bletest_set_adv_data(uint8_t *dptr, uint8_t *addr)
{
    uint8_t len;

    /* Place flags in first */
    dptr[0] = 0x02;
    dptr[1] = 0x01;     /* Flags identifier */
    dptr[2] = 0x06;
    dptr += 3;
    len = 3;

    /*  Add HID service */
    dptr[0] = 0x03;
    dptr[1] = 0x03;
    dptr[2] = 0x12;
    dptr[3] = 0x18;
    dptr += 4;
    len += 4;

    /* Add local name */
    dptr[0] = 12;   /* Length of this data, not including the length */
    dptr[1] = 0x09;
    dptr[2] = 'r';
    dptr[3] = 'u';
    dptr[4] = 'n';
    dptr[5] = 't';
    dptr[6] = 'i';
    dptr[7] = 'm';
    dptr[8] = 'e';
    dptr[9] = '-';
    dptr[10] = '0';
    dptr[11] = '0';
    dptr[12] = '7';
    dptr += 13;
    len += 13;

    /* Add local device address */
    dptr[0] = 0x08;
    dptr[1] = 0x1B;
    dptr[2] = 0x00;
    memcpy(dptr + 3, addr, BLE_DEV_ADDR_LEN);
    len += 9;

    g_host_adv_len = len;

    return len;
}

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
#if MYNEWT_VAL(BLE_ANDROID_MULTI_ADV_SUPPORT)
void
bletest_init_adv_instances(void)
{
    uint8_t i;
    int rc;
    uint8_t *addr;
    uint8_t adv_len;
    uint8_t inst_allowed;
    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
    struct hci_multi_adv_params adv;

    inst_allowed = MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES);
    if (inst_allowed > BLETEST_CFG_ADV_TEST_INSTANCES) {
        inst_allowed = BLETEST_CFG_ADV_TEST_INSTANCES;
    }

    /* Start up all the instances */
    for (i = 1; i <= inst_allowed; ++i) {
        memset(&adv, 0, sizeof(struct hci_multi_adv_params));

        adv.own_addr_type = bletest_multi_adv_instances[i-1].adv_own_addr_type;
        if (adv.own_addr_type == BLE_HCI_ADV_OWN_ADDR_PUBLIC) {
            addr = _g_dev_addr;
        } else {
            memcpy(rand_addr, _g_dev_addr, BLE_DEV_ADDR_LEN);
            rand_addr[5] |= 0xc0;
            rand_addr[0] = i;
            /*
             * NOTE: we overload own address type with a special case
             * to denote if we use own address or call to set multi random
             * address.
             */
            if (adv.own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
                rc = bletest_hci_le_set_multi_rand_addr(rand_addr, i);
                assert(rc == 0);
                addr = rand_addr;
            } else {
                adv.own_addr_type = BLE_HCI_ADV_OWN_ADDR_RANDOM;
                addr = rand_addr;
                memcpy(adv.own_addr, addr, BLE_DEV_ADDR_LEN);
            }
        }

        adv.adv_type = bletest_multi_adv_instances[i - 1].adv_type;
        adv.adv_channel_map = 0x07;
        adv.adv_filter_policy = BLE_HCI_ADV_FILT_NONE;
        adv.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC;
        adv_len = bletest_set_adv_data(&g_host_adv_data[0], addr);

        adv.adv_itvl_min = bletest_multi_adv_instances[i - 1].adv_itvl;
        adv.adv_itvl_max = bletest_multi_adv_instances[i - 1].adv_itvl;
        adv.adv_tx_pwr = -1 * i;

        /* Set the advertising parameters */
        rc = bletest_hci_le_set_multi_adv_params(&adv, i);
        assert(rc == 0);

        /* Set advertising data */
        if (adv_len != 0) {
            rc = bletest_hci_le_set_multi_adv_data(&g_host_adv_data[0], adv_len,
                                                   i);
            assert(rc == 0);

            /* Set scan response data */
            rc = bletest_hci_le_set_multi_scan_rsp_data(&g_host_adv_data[0],
                                                        adv_len, i);
            assert(rc == 0);
        }

        /* Set the advertising parameters */
        rc = bletest_hci_le_set_multi_adv_enable(1, i);
        assert(rc == 0);
    }
}

void
bletest_init_advertising(uint8_t instance, int8_t txpwr)
{
    int rc;
    int set_peer_addr;
    uint8_t adv_len;
    uint8_t *addr;
    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
    struct hci_multi_adv_params adv;

    /* Make sure it is a valid instance */
    assert(instance < BLE_LL_ADV_INSTANCES);

    /* Just zero out advertising */
    set_peer_addr = 0;
    memset(&adv, 0, sizeof(struct hci_multi_adv_params));

    /* If we are using a random address, we need to set it */
    adv.own_addr_type = BLETEST_CFG_ADV_OWN_ADDR_TYPE;
    if (adv.own_addr_type & 1) {
        memcpy(rand_addr, _g_dev_addr, BLE_DEV_ADDR_LEN);
        rand_addr[5] |= 0xc0;
        if (BLETEST_CFG_MULTI_ADV_RANDOM_OWN == 1) {
            addr = rand_addr;
            memcpy(adv.own_addr, addr, BLE_DEV_ADDR_LEN);
        } else {
            rc = bletest_hci_le_set_multi_rand_addr(rand_addr, instance);
            assert(rc == 0);
            addr = rand_addr;
        }
    } else {
        addr = _g_dev_addr;
    }

    /* Set advertising parameters */
    adv.adv_type = BLETEST_CFG_ADV_TYPE;
    adv.adv_channel_map = 0x07;
    adv.adv_filter_policy = BLETEST_CFG_ADV_FILT_POLICY;
    if ((adv.adv_filter_policy & 1) || (BLETEST_CFG_ADV_ADDR_RES_EN == 1)) {
        set_peer_addr = 1;
    }
    adv.peer_addr_type = BLETEST_CFG_ADV_PEER_ADDR_TYPE;
    if ((adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
        (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
        set_peer_addr = 1;
        adv_len = 0;
    } else {
        adv_len = bletest_set_adv_data(&g_host_adv_data[0], addr);
    }

    /* Not allowed for multi-adv command */
    if (adv.own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
        assert(0);
    }

    if (set_peer_addr) {
        memcpy(adv.peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
        if (adv.peer_addr_type == BLE_HCI_ADV_PEER_ADDR_RANDOM) {
            adv.peer_addr[5] |= 0xc0;
        }
    }

    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
                   adv.peer_addr[0], adv.peer_addr[1], adv.peer_addr[2],
                   adv.peer_addr[3], adv.peer_addr[4], adv.peer_addr[5]);

    if (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
        adv.adv_itvl_min = 0;
        adv.adv_itvl_max = 0;
    } else {
        adv.adv_itvl_min = BLETEST_CFG_ADV_ITVL;
        adv.adv_itvl_max = BLETEST_CFG_ADV_ITVL; /* Advertising interval */
    }

    adv.adv_tx_pwr = txpwr;

    /* Set the advertising parameters */
    rc = bletest_hci_le_set_multi_adv_params(&adv, instance);
    assert(rc == 0);

    /* Set advertising data */
    if (adv_len != 0) {
        rc = bletest_hci_le_set_multi_adv_data(&g_host_adv_data[0], adv_len,
                                               instance);
        assert(rc == 0);

        /* Set scan response data */
        rc = bletest_hci_le_set_multi_scan_rsp_data(&g_host_adv_data[0],adv_len,
                                                    instance);
        assert(rc == 0);
    }
}
#else
void
bletest_init_advertising(void)
{
    int rc;
    int set_peer_addr;
    uint8_t adv_len;
    uint8_t *addr;
    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
    struct hci_adv_params adv;

    /* Just zero out advertising */
    set_peer_addr = 0;
    memset(&adv, 0, sizeof(struct hci_adv_params));

    /* If we are using a random address, we need to set it */
    adv.own_addr_type = BLETEST_CFG_ADV_OWN_ADDR_TYPE;
    if (adv.own_addr_type & 1) {
        memcpy(rand_addr, _g_dev_addr, BLE_DEV_ADDR_LEN);
        rand_addr[5] |= 0xc0;
        rc = bletest_hci_le_set_rand_addr(rand_addr);
        assert(rc == 0);
        addr = rand_addr;
    } else {
        addr = _g_dev_addr;
    }

    /* Set advertising parameters */
    adv.adv_type = BLETEST_CFG_ADV_TYPE;
    adv.adv_channel_map = 0x07;
    adv.adv_filter_policy = BLETEST_CFG_ADV_FILT_POLICY;
    if ((adv.adv_filter_policy & 1) || (BLETEST_CFG_ADV_ADDR_RES_EN == 1)) {
        set_peer_addr = 1;
    }
    adv.peer_addr_type = BLETEST_CFG_ADV_PEER_ADDR_TYPE;
    if ((adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
        (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
        set_peer_addr = 1;
        adv_len = 0;
    } else {
        adv_len = bletest_set_adv_data(&g_host_adv_data[0], addr);
    }

    if (adv.own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
        set_peer_addr = 1;
    }

    if (set_peer_addr) {
        memcpy(adv.peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
        if (adv.peer_addr_type == BLE_HCI_ADV_PEER_ADDR_RANDOM) {
            adv.peer_addr[5] |= 0xc0;
        }
    }

    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
                   adv.peer_addr[0], adv.peer_addr[1], adv.peer_addr[2],
                   adv.peer_addr[3], adv.peer_addr[4], adv.peer_addr[5]);

    if (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
        adv.adv_itvl_min = 0;
        adv.adv_itvl_max = 0;
    } else {
        adv.adv_itvl_min = BLETEST_CFG_ADV_ITVL;
        adv.adv_itvl_max = BLETEST_CFG_ADV_ITVL; /* Advertising interval */
    }

    /* Set the advertising parameters */
    rc = bletest_hci_le_set_adv_params(&adv);
    assert(rc == 0);

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
    if ((adv.own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) ||
        (BLETEST_CFG_ADV_ADDR_RES_EN == 1)) {
        rc = bletest_hci_le_add_resolv_list(g_bletest_adv_irk,
                                            g_bletest_init_irk,
                                            adv.peer_addr,
                                            adv.peer_addr_type);
        assert(rc == 0);

        rc = bletest_hci_le_enable_resolv_list(1);
        assert(rc == 0);
    }
#endif

    /* Set advertising data */
    if (adv_len != 0) {
        rc = bletest_hci_le_set_adv_data(&g_host_adv_data[0], adv_len);
        assert(rc == 0);

        /* Set scan response data */
        rc = bletest_hci_le_set_scan_rsp_data(&g_host_adv_data[0], adv_len);
        assert(rc == 0);
    }
}
#endif  /* MULTI_ADV SUPPORT */
#endif  /* BLETEST_ROLE_ADVERTISER */

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
void
bletest_init_scanner(void)
{
    int rc;
    uint8_t own_addr_type;
    uint8_t buf[BLE_HCI_SET_SCAN_PARAM_LEN];
    uint8_t add_whitelist;

    own_addr_type = BLETEST_CFG_SCAN_OWN_ADDR_TYPE;
    rc = ble_hs_hci_cmd_build_le_set_scan_params(BLETEST_CFG_SCAN_TYPE,
                                               BLETEST_CFG_SCAN_ITVL,
                                               BLETEST_CFG_SCAN_WINDOW,
                                               own_addr_type,
                                               BLETEST_CFG_SCAN_FILT_POLICY,
                                               buf, sizeof buf);
    assert(rc == 0);
    rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
                                                BLE_HCI_OCF_LE_SET_SCAN_PARAMS),
                                                buf, sizeof(buf));
    assert(rc == 0);
    if (rc == 0) {
        add_whitelist = BLETEST_CFG_SCAN_FILT_POLICY;
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
        if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
            rc = bletest_hci_le_add_resolv_list(g_bletest_init_irk,
                                                g_bletest_adv_irk,
                                                g_bletest_cur_peer_addr,
                                                BLETEST_CFG_ADV_PEER_ADDR_TYPE);
            assert(rc == 0);

            rc = bletest_hci_le_enable_resolv_list(1);
            assert(rc == 0);
        }
#endif
        if (add_whitelist & 1) {
            rc = bletest_hci_le_add_to_whitelist(g_bletest_cur_peer_addr,
                                                 BLE_ADDR_RANDOM);
            assert(rc == 0);
        }
    }
}

void
bletest_execute_scanner(void)
{
    int rc;

    /* Enable scanning */
    if ((int32_t)(ble_npl_time_get() - g_next_os_time) >= 0) {
        if (g_bletest_state) {
            rc = bletest_hci_le_set_scan_enable(0, BLETEST_CFG_FILT_DUP_ADV);
            assert(rc == 0);
            g_bletest_state = 0;
        } else {
            rc = bletest_hci_le_set_scan_enable(1, BLETEST_CFG_FILT_DUP_ADV);
            assert(rc == 0);
            g_bletest_state = 1;
        }
        g_next_os_time += (OS_TICKS_PER_SEC * 60);
    }
}
#endif

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
void
bletest_init_initiator(void)
{
    int rc;
    uint8_t rand_addr[BLE_DEV_ADDR_LEN];
    struct hci_create_conn *hcc;

    /* Enable initiating */
    hcc = &g_cc;
    hcc->conn_itvl_max = BLETEST_CFG_CONN_ITVL;
    hcc->conn_itvl_min = BLETEST_CFG_CONN_ITVL;
    hcc->conn_latency = BLETEST_CFG_SLAVE_LATENCY;
    hcc->filter_policy = BLETEST_CFG_INIT_FILTER_POLICY;
    hcc->supervision_timeout = BLETEST_CFG_CONN_SPVN_TMO;
    hcc->scan_itvl = BLETEST_CFG_SCAN_ITVL;
    hcc->scan_window = BLETEST_CFG_SCAN_WINDOW;
    hcc->peer_addr_type = BLETEST_CFG_CONN_PEER_ADDR_TYPE;
    memcpy(hcc->peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
    if (hcc->peer_addr_type == BLE_HCI_CONN_PEER_ADDR_RANDOM) {
        hcc->peer_addr[5] |= 0xc0;
    }
    hcc->own_addr_type = BLETEST_CFG_CONN_OWN_ADDR_TYPE;
    hcc->min_ce_len = BLETEST_CFG_MIN_CE_LEN;
    hcc->max_ce_len = BLETEST_CFG_MAX_CE_LEN;

    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
                   hcc->peer_addr[0], hcc->peer_addr[1], hcc->peer_addr[2],
                   hcc->peer_addr[3], hcc->peer_addr[4], hcc->peer_addr[5]);

    /* If we are using a random address, we need to set it */
    if (hcc->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
        memcpy(rand_addr, _g_dev_addr, BLE_DEV_ADDR_LEN);
        rand_addr[5] |= 0xc0;
        rc = bletest_hci_le_set_rand_addr(rand_addr);
        assert(rc == 0);
    }

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
        if ((hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) ||
            (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM)) {
            rc = bletest_hci_le_add_resolv_list(g_bletest_init_irk,
                                                g_bletest_adv_irk,
                                                g_bletest_cur_peer_addr,
                                                BLETEST_CFG_ADV_PEER_ADDR_TYPE);
            assert(rc == 0);

            rc = bletest_hci_le_enable_resolv_list(1);
            assert(rc == 0);
        }
#endif

    bletest_hci_le_create_connection(hcc);
}

void
bletest_execute_initiator(void)
{
    int i;
    int rc;
    int8_t rssi;
    uint16_t handle;
    uint8_t new_chan_map[5];

    /*
     * Determine if there is an active connection for the current handle
     * we are trying to create. If so, start looking for the next one
     */
    if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
        handle = g_bletest_current_conns + 1;
        if (ble_hs_conn_find(handle)) {
            /* Set LED to slower blink rate */
            g_bletest_led_rate = OS_TICKS_PER_SEC;

            /* Ask for version information */
            rc = bletest_hci_rd_rem_version(handle);

            /* Ask for remote used features */
            rc = bletest_hci_le_read_rem_used_feat(handle);

            /* Add to current connections */
            if (!rc) {
                ++g_bletest_current_conns;

                /* Move to next connection */
                if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
                    /* restart initiating */
                    g_bletest_cur_peer_addr[5] += 1;
                    _g_dev_addr[5] += 1;
                    bletest_init_initiator();
                }
            }
        } else {
            bletest_hci_le_create_connection(&g_cc);
        }
    } else {
        if ((int32_t)(ble_npl_time_get() - g_next_os_time) >= 0) {
            if ((g_bletest_state == 1) || (g_bletest_state == 3)) {
                for (i = 0; i < g_bletest_current_conns; ++i) {
                    if (ble_hs_conn_find(i + 1)) {
                        bletest_hci_le_rd_chanmap(i+1);
                    }
                }
            } else if (g_bletest_state == 2) {
                new_chan_map[0] = 0;
                new_chan_map[1] = 0x3;
                new_chan_map[2] = 0;
                new_chan_map[3] = 0x1F;
                new_chan_map[4] = 0;
                bletest_hci_le_set_host_chan_class(new_chan_map);
            } else if (g_bletest_state == 4) {
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
                struct hci_start_encrypt hsle;
                for (i = 0; i < g_bletest_current_conns; ++i) {
                    if (ble_hs_conn_find(i + 1)) {
                        hsle.connection_handle = i + 1;
                        hsle.encrypted_diversifier = g_bletest_EDIV;
                        hsle.random_number = g_bletest_RAND;
                        swap_buf(hsle.long_term_key, (uint8_t *)g_bletest_LTK,
                                 16);
                        bletest_hci_le_start_encrypt(&hsle);
                    }
                }
#endif
            } else if (g_bletest_state == 8) {
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
                struct hci_start_encrypt hsle;
                for (i = 0; i < g_bletest_current_conns; ++i) {
                    if (ble_hs_conn_find(i + 1)) {
                        hsle.connection_handle = i + 1;
                        hsle.encrypted_diversifier = g_bletest_EDIV;
                        hsle.random_number = ~g_bletest_RAND;
                        swap_buf(hsle.long_term_key, (uint8_t *)g_bletest_LTK,
                                 16);
                        bletest_hci_le_start_encrypt(&hsle);
                    }
                }
#endif
            } else {
                for (i = 0; i < g_bletest_current_conns; ++i) {
                    if (ble_hs_conn_find(i + 1)) {
                        ble_hs_hci_util_read_rssi(i+1, &rssi);
                    }
                }
            }

            ++g_bletest_state;
            if (g_bletest_state > 9) {
                g_bletest_state = 9;
            }
            g_next_os_time = ble_npl_time_get() + OS_TICKS_PER_SEC * 3;
        }
    }
}
#endif

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
/*
 * Test wrapper to get packets. Only get a packet if we have more than half
 * left
 */
static struct os_mbuf *
bletest_get_packet(void)
{
    struct os_mbuf *om;

    om = NULL;
    if (os_msys_num_free() >= 5) {
        om = os_msys_get_pkthdr(0, sizeof(struct ble_mbuf_hdr));
    }
    return om;
}

static struct os_mbuf *
bletest_send_packet(uint16_t handle)
{
    int j;
    uint8_t val;
    struct os_mbuf *om;
    uint16_t pktlen;

    om = bletest_get_packet();
    if (om) {
        /* set payload length */
#if BLETEST_THROUGHPUT_TEST
        pktlen = BLETEST_PKT_SIZE;
#else
#if (BLETEST_CFG_RAND_PKT_SIZE == 1)
        pktlen = rand() % (BLETEST_MAX_PKT_SIZE + 1);
#else
        pktlen = BLETEST_PKT_SIZE;
#endif
#endif

        /* Put the HCI header in the mbuf */
        put_le16(om->om_data, handle);
        put_le16(om->om_data + 2, pktlen + 4);

        /* Place L2CAP header in packet */
        put_le16(om->om_data + 4, pktlen);
        om->om_data[6] = 0;
        om->om_data[7] = 0;
        om->om_len = 8;
        OS_MBUF_PKTHDR(om)->omp_len = 8;

        /* Fill with incrementing pattern (starting from 1) */
        for (j = 0; j < pktlen; ++j) {
            val = j + 1;
            os_mbuf_append(om, &val, 1);
        }

        /* Transmit it */
        ble_hci_trans_hs_acl_tx(om);
    }

    return om;
}

static void
bletest_execute_advertiser(void)
{
    int i;
#if (BLETEST_CONCURRENT_CONN_TEST == 1)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
    uint16_t mask;
    uint16_t reply_handle;
#endif
#endif
    int rc;
    uint16_t handle;
    struct os_mbuf *om;
#if (BLETEST_THROUGHPUT_TEST == 1)
    os_sr_t sr;
    uint16_t completed_pkts;
#endif

    /* See if we should start advertising again */
    if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
        handle = g_bletest_current_conns + 1;
        if (ble_hs_conn_find(handle)) {
            /* Set LED to slower blink rate */
            g_bletest_led_rate = OS_TICKS_PER_SEC;

#if (BLETEST_THROUGHPUT_TEST == 1)
            /* Set next os time to 10 seconds after 1st connection */
            if (g_next_os_time == 0) {
                g_next_os_time = os_time_get() + (10 * OS_TICKS_PER_SEC);
                g_bletest_handle = handle;
            }
#endif
            /* Send the remote used features command */
            rc = bletest_hci_le_read_rem_used_feat(handle);
            if (rc) {
                return;
            }

            /* Send the remote read version command */
            rc = bletest_hci_rd_rem_version(handle);
            if (rc) {
                return;
            }

            /* set conn update time */
            g_bletest_conn_upd_time = ble_npl_time_get() + (OS_TICKS_PER_SEC * 5);
            g_bletest_start_update = 1;

            /* Add to current connections */
            ++g_bletest_current_conns;

            /* Move to next connection */
            if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
                /* restart initiating */
                g_bletest_cur_peer_addr[5] += 1;
                _g_dev_addr[5] += 1;
#if MYNEWT_VAL(BLE_ANDROID_MULTI_ADV_SUPPORT)
                bletest_init_advertising(0,0);
                bletest_hci_le_set_multi_adv_enable(1, 0);
#else
                bletest_init_advertising();
                bletest_hci_le_set_adv_enable(1);
#endif
            }
        } else {
            /* If we failed to start advertising we should keep trying */
#if MYNEWT_VAL(BLE_ANDROID_MULTI_ADV_SUPPORT)
            bletest_hci_le_set_multi_adv_enable(1, 0);
#else
            bletest_hci_le_set_adv_enable(1);
#endif
        }
    }
#if 0
    if (g_bletest_start_update) {
        if ((int32_t)(os_time_get() - g_bletest_conn_upd_time) >= 0) {
            bletest_send_conn_update(1);
            g_bletest_start_update = 0;
        }
    }
#endif

#if (BLETEST_CONCURRENT_CONN_TEST == 1)
    /* See if it is time to hand a data packet to the connection */
    if ((int32_t)(ble_npl_time_get() - g_next_os_time) >= 0) {
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
        /* Do we need to send a LTK reply? */
        mask = 1;
        reply_handle = 1;
        while (g_bletest_ltk_reply_handle && mask) {
            if (g_bletest_ltk_reply_handle & mask) {
                bletest_send_ltk_req_reply(reply_handle);
                //bletest_send_ltk_req_neg_reply(reply_handle);
                g_bletest_ltk_reply_handle &= ~mask;
            }
            ++reply_handle;
            mask <<= 1;
        }
#endif
        if (g_bletest_current_conns) {
            for (i = 0; i < g_bletest_current_conns; ++i) {
                if ((g_last_handle_used == 0) ||
                    (g_last_handle_used > g_bletest_current_conns)) {
                    g_last_handle_used = 1;
                }
                handle = g_last_handle_used;
                if (ble_hs_conn_find(handle)) {
                    om = bletest_send_packet(handle);
                    if (om) {
                        /* Increment last handle used */
                        ++g_last_handle_used;
                    }
                } else {
                    ++g_last_handle_used;
                }
            }
        }
        g_next_os_time = ble_npl_time_get() + OS_TICKS_PER_SEC;
    }
#endif

#if (BLETEST_THROUGHPUT_TEST == 1)
    /* Nothing to do if no connections */
    if (!g_bletest_current_conns) {
        return;
    }

    /* See if it is time to start throughput testing */
    if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
        /* Keep window full */
        OS_ENTER_CRITICAL(sr);
        completed_pkts = g_bletest_completed_pkts;
        g_bletest_completed_pkts = 0;
        OS_EXIT_CRITICAL(sr);

        assert(g_bletest_outstanding_pkts >= completed_pkts);
        g_bletest_outstanding_pkts -= completed_pkts;

        while (g_bletest_outstanding_pkts < 20) {
            om = bletest_send_packet(g_bletest_handle);
            if (om) {
                ++g_bletest_outstanding_pkts;
            }
        }
    }
#endif /* XXX: throughput test */
}
#endif /* XXX: BLETEST_ROLE_ADVERTISER */

/**
 * Main bletest function. Called by the task timer every 50 msecs.
 *
 */
void
bletest_execute(void)
{
    /* Toggle LED at set rate */
    if ((int32_t)(ble_npl_time_get() - g_bletest_next_led_time) >= 0) {
        // hal_gpio_toggle(LED_BLINK_PIN);
        g_bletest_next_led_time = ble_npl_time_get() + g_bletest_led_rate;
    }
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
    bletest_execute_advertiser();
#endif
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
    bletest_execute_scanner();
#endif
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
    bletest_execute_initiator();
#endif
}

/**
 * Callback when BLE test timer expires.
 *
 * @param arg
 */
void
bletest_timer_cb(struct ble_npl_event *ev)
{
    /* Call the bletest code */
    bletest_execute();

    /* Re-start the timer (run every 10 msecs) */
    ble_npl_callout_reset(&g_bletest_timer, OS_TICKS_PER_SEC / 100);
}

/**
 * BLE test task
 *
 * @param arg
 */
void
bletest_task_handler(void *arg)
{
    int rc;
    uint64_t rand64;
    uint64_t event_mask;

    /* Set LED blink rate */
    g_bletest_led_rate = OS_TICKS_PER_SEC / 20;

    /* Wait one second before starting test task */
    ble_npl_time_delay(OS_TICKS_PER_SEC);

    /* Initialize the host timer */
    ble_npl_callout_init(&g_bletest_timer, &g_bletest_evq, bletest_timer_cb,
                    NULL);

    ble_hs_dbg_set_sync_state(BLE_HS_SYNC_STATE_GOOD);

    /* Send the reset command first */
    rc = bletest_hci_reset_ctlr();
    assert(rc == 0);

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
    /* Initialize the advertiser */
    console_printf("Starting BLE test task as advertiser\n");
#if MYNEWT_VAL(BLE_ANDROID_MULTI_ADV_SUPPORT)
    /* Start up all advertising instances except default one */
    bletest_init_adv_instances();

    /* Start advertising on instance 0 at 0 dbm */
    bletest_init_advertising(0, 0);
#else
    bletest_init_advertising();
#endif
#endif

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
    /* Initialize the scanner */
    console_printf("Starting BLE test task as scanner\n");
    bletest_init_scanner();
#endif

#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
    /* Initialize the scanner */
    console_printf("Starting BLE test task as initiator\n");
    bletest_init_initiator();
#endif

    /* Read unique HW id */
    // rc = hal_bsp_hw_id((void *)&g_bletest_hw_id[0], sizeof(g_bletest_hw_id));
    // assert(rc == 16);
    console_printf("HW id=%04x%04x%04x%04x\n",
                   (unsigned int)g_bletest_hw_id[0],
                   (unsigned int)g_bletest_hw_id[1],
                   (unsigned int)g_bletest_hw_id[2],
                   (unsigned int)g_bletest_hw_id[3]);

    /* Set the event mask we want to display */
    event_mask = 0x7FF;
    rc = bletest_hci_le_set_event_mask(event_mask);
    assert(rc == 0);

    /* Turn on all events */
    event_mask = 0xffffffffffffffff;
    rc = bletest_hci_set_event_mask(event_mask);
    assert(rc == 0);

    /* Read device address */
    rc = bletest_hci_rd_bd_addr();
    assert(rc == 0);

    /* Read local features */
    rc = bletest_hci_rd_local_feat();
    assert(rc == 0);

    /* Read local commands */
    rc = bletest_hci_rd_local_supp_cmd();
    assert(rc == 0);

    /* Read version */
    rc = bletest_hci_rd_local_version();
    assert(rc == 0);

    /* Read supported states */
    rc = bletest_hci_le_read_supp_states();
    assert(rc == 0);

    /* Read maximum data length */
    rc = bletest_hci_le_rd_max_datalen();
    assert(rc == 0);

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) == 1)
    /* Read suggested data length */
    rc = bletest_hci_le_rd_sugg_datalen();
    assert(rc == 0);

    /* write suggested default data length */
    rc = bletest_hci_le_write_sugg_datalen(BLETEST_CFG_SUGG_DEF_TXOCTETS,
                                           BLETEST_CFG_SUGG_DEF_TXTIME);
    assert(rc == 0);

    /* Read suggested data length */
    rc = bletest_hci_le_rd_sugg_datalen();
    assert(rc == 0);

    /* Set data length (note: we know there is no connection; just a test) */
    rc = bletest_hci_le_set_datalen(0x1234, BLETEST_CFG_SUGG_DEF_TXOCTETS,
                                    BLETEST_CFG_SUGG_DEF_TXTIME);
    assert(rc != 0);
#endif

    /* Encrypt a block */
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
    rc = bletest_hci_le_encrypt((uint8_t *)g_ble_ll_encrypt_test_key,
                                (uint8_t *)g_ble_ll_encrypt_test_plain_text);
    assert(rc == 0);
#endif

    /* Get a random number */
    rc = ble_hs_hci_util_rand(&rand64, 8);
    assert(rc == 0);

    /* Wait some time before starting */
    ble_npl_time_delay(OS_TICKS_PER_SEC);

    /* Init state */
    g_bletest_state = 0;

    /* Begin advertising if we are an advertiser */
#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
#if MYNEWT_VAL(BLE_ANDROID_MULTI_ADV_SUPPORT)
    rc = bletest_hci_le_set_multi_adv_enable(1, 0);
    assert(rc == 0);
#else
    rc = bletest_hci_le_set_adv_enable(1);
    assert(rc == 0);
#endif
#endif

    bletest_timer_cb(NULL);
}

extern int nimble_ble_enable(void);
/**
 * main
 *
 * The main task for the project. This function initializes the packages,
 * then starts serving events from default event queue.
 *
 * @return int NOTE: this function should never return!
 */
static int bletest(void)
{
    rt_thread_t tid;

    /* startup bluetooth host stack*/
    ble_hs_thread_startup();

    /* Dummy device address */
#if BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER
    _g_dev_addr[0] = 0x00;
    _g_dev_addr[1] = 0x00;
    _g_dev_addr[2] = 0x00;
    _g_dev_addr[3] = 0x88;
    _g_dev_addr[4] = 0x88;
    _g_dev_addr[5] = 0x08;

    g_bletest_cur_peer_addr[0] = 0x00;
    g_bletest_cur_peer_addr[1] = 0x00;
    g_bletest_cur_peer_addr[2] = 0x00;
    g_bletest_cur_peer_addr[3] = 0x99;
    g_bletest_cur_peer_addr[4] = 0x99;
    g_bletest_cur_peer_addr[5] = 0x09;
#else
    _g_dev_addr[0] = 0x00;
    _g_dev_addr[1] = 0x00;
    _g_dev_addr[2] = 0x00;
    _g_dev_addr[3] = 0x99;
    _g_dev_addr[4] = 0x99;
    _g_dev_addr[5] = 0x09;

    g_bletest_cur_peer_addr[0] = 0x00;
    g_bletest_cur_peer_addr[1] = 0x00;
    g_bletest_cur_peer_addr[2] = 0x00;
    g_bletest_cur_peer_addr[3] = 0x88;
    g_bletest_cur_peer_addr[4] = 0x88;
    g_bletest_cur_peer_addr[5] = 0x08;
#endif

    /* Set the led pin as an output */
    // g_led_pin = LED_BLINK_PIN;
    // hal_gpio_init_out(g_led_pin, 1);

    /* Initialize eventq for bletest task */
    ble_npl_eventq_init(&g_bletest_evq);
    
    tid = rt_thread_create("ble_test", bletest_task_handler, RT_NULL, 1024, 10, 10);
    if(tid != RT_NULL)
        rt_thread_startup(tid);

    return 0;
}
MSH_CMD_EXPORT_ALIAS(bletest, bletest, "bluetooth test sample");
