diff --git a/port/nrf5-zephyr/Kconfig b/port/nrf5-zephyr/Kconfig new file mode 100644 index 000000000..b9fe16707 --- /dev/null +++ b/port/nrf5-zephyr/Kconfig @@ -0,0 +1,5 @@ +menuconfig BTSTACK + bool "BTstack support" + default n + help + This option enables the BTstack Bluetooth stack. diff --git a/port/nrf5-zephyr/Makefile b/port/nrf5-zephyr/Makefile new file mode 100644 index 000000000..422972908 --- /dev/null +++ b/port/nrf5-zephyr/Makefile @@ -0,0 +1,5 @@ +KERNEL_TYPE = nano +CONF_FILE ?= nrf5.conf +BOARD ?= nrf52_pca10040 + +include ${ZEPHYR_BASE}/Makefile.inc diff --git a/port/nrf5-zephyr/Makefile.ble b/port/nrf5-zephyr/Makefile.ble new file mode 100644 index 000000000..6539eb25f --- /dev/null +++ b/port/nrf5-zephyr/Makefile.ble @@ -0,0 +1,14 @@ +obj-y += \ + ancs_client.o \ + att_db.o \ + att_dispatch.o \ + att_server.o \ + gatt_client.o \ + le_device_db_memory.o \ + sm.o \ + sm_mbedtls_allocator.o \ + +# att_db_util.o \ + +obj-y += gatt-service/ +ccflags-y += -I${ZEPHYR_BASE}/subsys/btstack diff --git a/port/nrf5-zephyr/Makefile.gatt-service b/port/nrf5-zephyr/Makefile.gatt-service new file mode 100644 index 000000000..6f7c43a39 --- /dev/null +++ b/port/nrf5-zephyr/Makefile.gatt-service @@ -0,0 +1,4 @@ +obj-y += \ + battery_service_server.o \ + +ccflags-y += -I${ZEPHYR_BASE}/subsys/btstack diff --git a/port/nrf5-zephyr/Makefile.src b/port/nrf5-zephyr/Makefile.src new file mode 100644 index 000000000..6b63889e5 --- /dev/null +++ b/port/nrf5-zephyr/Makefile.src @@ -0,0 +1,20 @@ +obj-y += \ + ad_parser.o \ + btstack_linked_list.o \ + btstack_memory.o \ + btstack_memory_pool.o \ + btstack_ring_buffer.o \ + btstack_run_loop.o \ + btstack_slip.o \ + btstack_util.o \ + hci.o \ + hci_cmd.o \ + hci_dump.o \ + hci_transport_h4.o \ + hci_transport_h5.o \ + l2cap.o \ + l2cap_signaling.o \ + btstack_run_loop_embedded.o \ + +obj-y += ble/ +ccflags-y += -I${ZEPHYR_BASE}/subsys/btstack diff --git a/port/nrf5-zephyr/btstack_config.h b/port/nrf5-zephyr/btstack_config.h new file mode 100644 index 000000000..4427c2c07 --- /dev/null +++ b/port/nrf5-zephyr/btstack_config.h @@ -0,0 +1,34 @@ +// +// btstack_config.h for mRF5-Zephyr port +// + +#ifndef __BTSTACK_CONFIG +#define __BTSTACK_CONFIG + +// Port related features + +// BTstack features that can be enabled +#define ENABLE_BLE +#define ENABLE_LOG_INFO +#define ENABLE_LOG_ERROR + +// BTstack configuration. buffers, sizes, ... +#define HCI_ACL_PAYLOAD_SIZE 52 +#define MAX_NR_WHITELIST_ENTRIES 1 +#define MAX_NR_HCI_CONNECTIONS 1 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 +#define MAX_NR_L2CAP_SERVICES 1 +#define MAX_NR_L2CAP_CHANNELS 1 +#define MAX_NR_GATT_CLIENTS 1 +#define MAX_NR_GATT_SUBCLIENTS 1 + +#define MAX_NR_RFCOMM_MULTIPLEXERS 0 +#define MAX_NR_RFCOMM_SERVICES 0 +#define MAX_NR_RFCOMM_CHANNELS 0 +#define MAX_NR_HFP_CONNECTIONS 0 +#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0 +#define MAX_NR_BNEP_SERVICES 0 +#define MAX_NR_BNEP_CHANNELS 0 +#define MAX_NR_SERVICE_RECORD_ITEMS 1 + +#endif \ No newline at end of file diff --git a/port/nrf5-zephyr/create_examples.py b/port/nrf5-zephyr/create_examples.py new file mode 100755 index 000000000..79f7f90f8 --- /dev/null +++ b/port/nrf5-zephyr/create_examples.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# Create project files for all BTstack embedded examples in zephyr/samples/btstack + +import os +import shutil +import sys +import time +import subprocess + +mk_template = '''# +# BTstack example 'EXAMPLE' for nRF5-zephyr port +# +# Generated by TOOL +# On DATE + +obj-y += EXAMPLE.o +obj-y += main.o +ccflags-y += -I${ZEPHYR_BASE}/subsys/btstack +ccflags-y += -I${ZEPHYR_BASE}/subsys/bluetooth/controller/ll + +''' + +gatt_update_template = '''#!/bin/sh +DIR=`dirname $0` +BTSTACK_ROOT=$DIR/../../../btstack +echo "Creating src/EXAMPLE.h from EXAMPLE.gatt" +$BTSTACK_ROOT/tool/compile_gatt.py $BTSTACK_ROOT/example/EXAMPLE.gatt $DIR/src/EXAMPLE.h +''' + +# get script path +script_path = os.path.abspath(os.path.dirname(sys.argv[0])) + +# validate nRF5x SDK root by reading include/zephyr.h +zpehyr_base = script_path + "/../../../" + +zephyr_h = "" +try: + with open(zpehyr_base + '/include/zephyr.h', 'r') as fin: + zephyr_h = fin.read() # Read the contents of the file into memory. +except: + pass +if not "_ZEPHYR__H" in zephyr_h: + print("Cannot find Zpehyr root. Make sure BTstack is checked out as zephyr/btstack") + sys.exit(1) + +# path to examples +examples_embedded = script_path + "/../../example/" + +# path to zephyr/samples/btstack +apps_btstack = zpehyr_base + "/samples/btstack/" + +print("Creating examples in samples/btstack:") + +# iterate over btstack examples +for file in os.listdir(examples_embedded): + if not file.endswith(".c"): + continue + + example = file[:-2] + gatt_path = examples_embedded + example + ".gatt" + + # filter LE-only applications + if not os.path.exists(gatt_path) and not example in [ + "ancs_cient_demo","gap_le_advertisements", "gatt_battery_query","gatt_browser","sm_pairing_central"]: + continue + if example == "spp_and_le_counter": + continue + + # create folder + apps_folder = apps_btstack + example + "/" + if not os.path.exists(apps_folder): + os.makedirs(apps_folder) + + # copy nrf5.conf + shutil.copyfile(script_path + '/nrf5.conf', apps_folder + '/nrf5.conf') + + # copy Makefile + shutil.copyfile(script_path + '/Makefile', apps_folder + 'Makefile') + + # create src folder + src_folder = apps_folder + "src/" + if not os.path.exists(src_folder): + os.makedirs(src_folder) + + # create Makefile file + with open(src_folder + "Makefile", "wt") as fout: + fout.write(mk_template.replace("EXAMPLE", example).replace("TOOL", script_path).replace("DATE",time.strftime("%c"))) + + # copy port main.c + shutil.copyfile(script_path + '/main.c', src_folder + "/main.c") + + # copy example file + shutil.copyfile(examples_embedded + file, src_folder + "/" + example + ".c") + + # create update_gatt.sh if .gatt file is present + gatt_path = examples_embedded + example + ".gatt" + if os.path.exists(gatt_path): + update_gatt_script = apps_folder + "update_gatt_db.sh" + with open(update_gatt_script, "wt") as fout: + fout.write(gatt_update_template.replace("EXAMPLE", example)) + os.chmod(update_gatt_script, 0o755) + subprocess.call(update_gatt_script + "> /dev/null", shell=True) + print("- %s including compiled GATT DB" % example) + else: + print("- %s" % example) + diff --git a/port/nrf5-zephyr/integrate_btstack.sh b/port/nrf5-zephyr/integrate_btstack.sh new file mode 100755 index 000000000..ec12b59c1 --- /dev/null +++ b/port/nrf5-zephyr/integrate_btstack.sh @@ -0,0 +1,42 @@ +#/bin/sh + +ZEPHYR_BASE=../../.. + +echo "Adding BTstack sources as subsys/btstack" + +# add btstack folder to subsys/Makefile +MAKEFILE_ADD_ON='obj-$(CONFIG_BTSTACK) += btstack/' +NET_MAKEFILE=${ZEPHYR_BASE}/subsys/Makefile +grep -q -F btstack ${NET_MAKEFILE} || echo ${MAKEFILE_ADD_ON} >> ${NET_MAKEFILE} + +# add BTstack KConfig to net/Kconfig +SUBSYS_KCONFIG=${ZEPHYR_BASE}/subsys/Kconfig +grep -q -F btstack ${SUBSYS_KCONFIG} || echo 'source "subsys/btstack/Kconfig"' >> ${SUBSYS_KCONFIG} + +# create net/btstack +mkdir -p ${ZEPHYR_BASE}/subsys/btstack + +# copy sources +rsync -a ../../src/ ${ZEPHYR_BASE}/subsys/btstack + +# copy embedded run loop +rsync -a ../../platform/embedded/hal_cpu.h ${ZEPHYR_BASE}/subsys/btstack +rsync -a ../../platform/embedded/hal_time_ms.h ${ZEPHYR_BASE}/subsys/btstack +rsync -a ../../platform/embedded/hal_tick.h ${ZEPHYR_BASE}/subsys/btstack +rsync -a ../../platform/embedded/btstack_run_loop_embedded.h ${ZEPHYR_BASE}/subsys/btstack +rsync -a ../../platform/embedded/btstack_run_loop_embedded.c ${ZEPHYR_BASE}/subsys/btstack + +# copy btstack_config.h +rsync -a btstack_config.h ${ZEPHYR_BASE}/subsys/btstack + +# copy Kconfig +rsync -a Kconfig ${ZEPHYR_BASE}/subsys/btstack + +# copy Makefiles +rsync -a Makefile.src ${ZEPHYR_BASE}/subsys/btstack/Makefile +rsync -a Makefile.ble ${ZEPHYR_BASE}/subsys/btstack/ble/Makefile +rsync -a Makefile.gatt-service ${ZEPHYR_BASE}/subsys/btstack/ble/gatt-service/Makefile + +# create samples/btstack +./create_examples.py + diff --git a/port/nrf5-zephyr/main.c b/port/nrf5-zephyr/main.c new file mode 100644 index 000000000..13d535c43 --- /dev/null +++ b/port/nrf5-zephyr/main.c @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + /** + * BTstack port for Zephyr Bluetooth Controller + * + * Data Sources aside from the HCI Controller are not supported yet + * Timers are supported by waiting on the HCI Controller RX queue until the next timeout is due + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "ll.h" + +#include + +#include "btstack_debug.h" +#include "btstack_event.h" +#include "btstack_memory.h" +#include "btstack_run_loop.h" +#include "hci.h" +#include "hci_dump.h" +#include "hci_transport.h" + +static btstack_packet_callback_registration_t hci_event_callback_registration; + +static void (*transport_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size); + +// +// hci_transport_zephyr.c +// + +/* HCI command buffers */ +#define CMD_BUF_SIZE (CONFIG_BLUETOOTH_HCI_SEND_RESERVE + \ + sizeof(struct bt_hci_cmd_hdr) + \ + CONFIG_BLUETOOTH_MAX_CMD_LEN) + +static struct nano_fifo avail_cmd_tx; +static NET_BUF_POOL(cmd_tx_pool, CONFIG_BLUETOOTH_HCI_CMD_COUNT, CMD_BUF_SIZE, + &avail_cmd_tx, NULL, BT_BUF_USER_DATA_MIN); + +#define BT_L2CAP_MTU 64 +/** Data size needed for ACL buffers */ +#define BT_BUF_ACL_SIZE (CONFIG_BLUETOOTH_HCI_RECV_RESERVE + \ + sizeof(struct bt_hci_acl_hdr) + \ + 4 /* L2CAP header size */ + \ + BT_L2CAP_MTU) + +static struct nano_fifo avail_acl_tx; +static NET_BUF_POOL(acl_tx_pool, CONFIG_BLUETOOTH_CONTROLLER_TX_BUFFERS, + BT_BUF_ACL_SIZE, &avail_acl_tx, NULL, BT_BUF_USER_DATA_MIN); + +static struct nano_fifo rx_queue; +static struct nano_fifo tx_queue; + +/** + * init transport + * @param transport_config + */ +static void transport_init(const void *transport_config){ + /* Initialize the buffer pools */ + net_buf_pool_init(cmd_tx_pool); + net_buf_pool_init(acl_tx_pool); + + /* Initialize the FIFOs */ + nano_fifo_init(&tx_queue); + nano_fifo_init(&rx_queue); + + /* startup Controller */ + bt_enable_raw(&rx_queue); + + // use 11:22:33:44:55:66 + uint8_t addr[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + ll_address_set(0, addr); +} + +/** + * open transport connection + */ +static int transport_open(void){ + return 0; +} + +/** + * close transport connection + */ +static int transport_close(void){ + return 0; +} + +/** + * register packet handler for HCI packets: ACL, SCO, and Events + */ +static void transport_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){ + transport_packet_handler = handler; +} + +static void send_hardware_error(uint8_t error_code){ + // hci_outgoing_event[0] = HCI_EVENT_HARDWARE_ERROR; + // hci_outgoing_event[1] = 1; + // hci_outgoing_event[2] = error_code; + // hci_outgoing_event_ready = 1; +} + +static int transport_send_packet(uint8_t packet_type, uint8_t *packet, int size){ + struct net_buf *buf; + switch (packet_type){ + case HCI_COMMAND_DATA_PACKET: + buf = net_buf_get(&avail_cmd_tx, 0); + if (buf) { + bt_buf_set_type(buf, BT_BUF_CMD); + memcpy(net_buf_add(buf, size), packet, size); + bt_send(buf); + } else { + log_error("No available command buffers!\n"); + } + break; + case HCI_ACL_DATA_PACKET: + buf = net_buf_get(&avail_acl_tx, 0); + if (buf) { + bt_buf_set_type(buf, BT_BUF_ACL_OUT); + memcpy(net_buf_add(buf, size), packet, size); + bt_send(buf); + } else { + log_error("No available ACL buffers!\n"); + } + break; + default: + send_hardware_error(0x01); // invalid HCI packet + break; + } + + return 0; +} + +static const hci_transport_t transport = { + /* const char * name; */ "nRF5-Zephyr", + /* void (*init) (const void *transport_config); */ &transport_init, + /* int (*open)(void); */ &transport_open, + /* int (*close)(void); */ &transport_close, + /* void (*register_packet_handler)(void (*handler)(...); */ &transport_register_packet_handler, + /* int (*can_send_packet_now)(uint8_t packet_type); */ NULL, + /* int (*send_packet)(...); */ &transport_send_packet, + /* int (*set_baudrate)(uint32_t baudrate); */ NULL, + /* void (*reset_link)(void); */ NULL, +}; + +static const hci_transport_t * transport_get_instance(void){ + return &transport; +} + +static void transport_deliver_controller_packet(struct net_buf * buf){ + uint16_t size = buf->len; + uint8_t * packet = buf->data; + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_IN: + transport_packet_handler(HCI_ACL_DATA_PACKET, packet, size); + break; + case BT_BUF_EVT: + transport_packet_handler(HCI_EVENT_PACKET, packet, size); + break; + default: + log_error("Unknown type %u\n", bt_buf_get_type(buf)); + net_buf_unref(buf); + break; + } + net_buf_unref(buf); +} + +// btstack_run_loop_zephry.c + +// the run loop +static btstack_linked_list_t timers; + +static int sys_clock_ms_per_tick; // set in btstack_run_loop_zephyr_init() + +static uint32_t btstack_run_loop_zephyr_get_time_ms(void){ + return sys_tick_get_32() * sys_clock_ms_per_tick; +} + +static uint32_t btstack_run_loop_zephyr_ticks_for_ms(uint32_t time_in_ms){ + return time_in_ms / sys_clock_ms_per_tick; +} + +static void btstack_run_loop_zephyr_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms){ + uint32_t ticks = btstack_run_loop_zephyr_ticks_for_ms(timeout_in_ms); + if (ticks == 0) ticks++; + // time until next tick is < hal_tick_get_tick_period_in_ms() and we don't know, so we add one + ts->timeout = sys_tick_get_32() + 1 + ticks; +} + +/** + * Add timer to run_loop (keep list sorted) + */ +static void btstack_run_loop_zephyr_add_timer(btstack_timer_source_t *ts){ + btstack_linked_item_t *it; + for (it = (btstack_linked_item_t *) &timers; it->next ; it = it->next){ + // don't add timer that's already in there + if ((btstack_timer_source_t *) it->next == ts){ + log_error( "btstack_run_loop_timer_add error: timer to add already in list!"); + return; + } + if (ts->timeout < ((btstack_timer_source_t *) it->next)->timeout) { + break; + } + } + ts->item.next = it->next; + it->next = (btstack_linked_item_t *) ts; +} + +/** + * Remove timer from run loop + */ +static int btstack_run_loop_zephyr_remove_timer(btstack_timer_source_t *ts){ + return btstack_linked_list_remove(&timers, (btstack_linked_item_t *) ts); +} + +static void btstack_run_loop_zephyr_dump_timer(void){ +#ifdef ENABLE_LOG_INFO + btstack_linked_item_t *it; + int i = 0; + for (it = (btstack_linked_item_t *) timers; it ; it = it->next){ + btstack_timer_source_t *ts = (btstack_timer_source_t*) it; + log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout); + } +#endif +} + +/** + * Execute run_loop + */ +static void btstack_run_loop_zephyr_execute(void) { + while (1) { + // get next timeout + int32_t timeout_ticks = TICKS_UNLIMITED; + if (timers) { + btstack_timer_source_t * ts = (btstack_timer_source_t *) timers; + uint32_t now = sys_tick_get_32(); + if (ts->timeout < now){ + // remove timer before processing it to allow handler to re-register with run loop + btstack_run_loop_remove_timer(ts); + // printf("RL: timer %p\n", ts->process); + ts->process(ts); + continue; + } + timeout_ticks = ts->timeout - now; + } + + // process RX fifo only + struct net_buf *buf = net_buf_get_timeout(&rx_queue, 0, timeout_ticks); + if (buf){ + transport_deliver_controller_packet(buf); + } + } +} + +static void btstack_run_loop_zephyr_btstack_run_loop_init(void){ + timers = NULL; + sys_clock_ms_per_tick = sys_clock_us_per_tick / 1000; + log_info("btstack_run_loop_init: ms_per_tick %u", sys_clock_ms_per_tick); +} + +static const btstack_run_loop_t btstack_run_loop_wiced = { + &btstack_run_loop_zephyr_btstack_run_loop_init, + NULL, + NULL, + NULL, + NULL, + &btstack_run_loop_zephyr_set_timer, + &btstack_run_loop_zephyr_add_timer, + &btstack_run_loop_zephyr_remove_timer, + &btstack_run_loop_zephyr_execute, + &btstack_run_loop_zephyr_dump_timer, + &btstack_run_loop_zephyr_get_time_ms, +}; +/** + * @brief Provide btstack_run_loop_posix instance for use with btstack_run_loop_init + */ +const btstack_run_loop_t * btstack_run_loop_zephyr_get_instance(void){ + return &btstack_run_loop_wiced; +} + +// main.c + +static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + if (packet_type != HCI_EVENT_PACKET) return; + if (hci_event_packet_get_type(packet) != BTSTACK_EVENT_STATE) return; + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; + printf("BTstack up and running.\n"); +} + +int btstack_main(void); + +void main(void) +{ + printf("BTstack booting up..\n"); + + // start with BTstack init - especially configure HCI Transport + btstack_memory_init(); + btstack_run_loop_init(btstack_run_loop_zephyr_get_instance()); + + // enable full log output while porting + hci_dump_open(NULL, HCI_DUMP_STDOUT); + + // init HCI + hci_init(transport_get_instance(), NULL); + + // inform about BTstack state + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + + // hand over to btstack embedded code + btstack_main(); + + // go + btstack_run_loop_execute(); + + while (1){}; +} diff --git a/port/nrf5-zephyr/net-Kconfig.patch b/port/nrf5-zephyr/net-Kconfig.patch new file mode 100644 index 000000000..1353b2f94 --- /dev/null +++ b/port/nrf5-zephyr/net-Kconfig.patch @@ -0,0 +1,11 @@ +--- Kconfig 2016-11-03 15:27:17.000000000 +0100 ++++ Kconfig-new 2016-11-04 10:59:50.000000000 +0100 +@@ -20,6 +20,8 @@ + + source "net/bluetooth/Kconfig" + ++source "net/btstack/Kconfig" ++ + source "net/ip/Kconfig" + + config NET_BUF diff --git a/port/nrf5-zephyr/nrf5.conf b/port/nrf5-zephyr/nrf5.conf new file mode 100644 index 000000000..8bbaba96d --- /dev/null +++ b/port/nrf5-zephyr/nrf5.conf @@ -0,0 +1,18 @@ +CONFIG_CONSOLE=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_NRF5_BAUD_RATE=115200 +# CONFIG_UART_NRF5_FLOW_CONTROL=y + +CONFIG_GPIO=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +CONFIG_BLUETOOTH=y +CONFIG_BLUETOOTH_STACK_HCI_RAW=y +CONFIG_BLUETOOTH_MAX_CONN=16 +CONFIG_BLUETOOTH_CONTROLLER_RX_BUFFERS=4 +CONFIG_BLUETOOTH_CONTROLLER_TX_BUFFERS=4 + +CONFIG_BTSTACK=y +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/port/nrf5-zephyr/readme.md b/port/nrf5-zephyr/readme.md new file mode 100644 index 000000000..ab5294358 --- /dev/null +++ b/port/nrf5-zephyr/readme.md @@ -0,0 +1,31 @@ +# Experimental port of BTstack to Zephyr running on Nordic nRF5 Series + +## Overview + +This port targets the bare Nordic nRF5-Series chipsets with the BLE Link Layer provided by the Zephyr project. + +## Status + +Working with nRF52 pca10040 dev board. Public BD ADDR is set to 11:22:33:44:55:66 since the default 00:00:00:00:00:00 is filtered by iOS. + +## Getting Started + +To integrate BTstack into Zephyr, please move the BTstack project into the Zephyr root folder 'zephyr'. + +Then integrate BTstack: + + cd /path/to/zephy/btstack/port/nrf5-zephyr + ./integrate_btstack.sh + +Now, the BTstack examples can be build from the Zephyr examples folder in the same way as other examples, e.g.: + + cd /path/to/zephyr/samples/btstack/le_counter + make + +to build the le_counter example for the pca10040 dev kit using the ARM GCC compiler. + +See nRF5 SDK documentation about how to install it. + +All examples that provide a GATT Server use the GATT DB in the .gatt file. Therefore you need to run ./update_gatt_db.sh in the example folder after modifying the .gatt file. + +This port does not support Data Sources aside from the HCI Controller. diff --git a/src/btstack_linked_list.c b/src/btstack_linked_list.c index 6c1d7c9d3..bb5d9fcad 100644 --- a/src/btstack_linked_list.c +++ b/src/btstack_linked_list.c @@ -95,11 +95,6 @@ void btstack_linked_list_add_tail(btstack_linked_list_t * list, btstack_linked_i it->next = item; } -/** - * Remove data_source from run loop - * - * @note: assumes that btstack_data_source_t.next is first element in data_source - */ int btstack_linked_list_remove(btstack_linked_list_t * list, btstack_linked_item_t *item){ // <-- remove item from list if (!item) return -1; btstack_linked_item_t *it; @@ -124,6 +119,20 @@ int btstack_linked_list_remove(btstack_linked_list_t * list, btstack_linked_ite return counter; } +// get first element +btstack_linked_item_t * btstack_linked_list_get_first_item(btstack_linked_list_t * list){ + return * list; +} + +// pop (get + remove) first element +btstack_linked_item_t * btstack_linked_list_pop(btstack_linked_list_t * list){ + btstack_linked_item_t * item = *list; + if (!item) return NULL; + *list = item->next; + return item; +} + + // // Linked List Iterator implementation // diff --git a/src/btstack_linked_list.h b/src/btstack_linked_list.h index ce5484e0d..0183ff4f8 100644 --- a/src/btstack_linked_list.h +++ b/src/btstack_linked_list.h @@ -64,9 +64,13 @@ int btstack_linked_list_empty(btstack_linked_list_t * list); // add item to list as first element void btstack_linked_list_add(btstack_linked_list_t * list, btstack_linked_item_t *item); // add item to list as last element -void btstack_linked_list_add_tail(btstack_linked_list_t * list, btstack_linked_item_t *item); +void btstack_linked_list_add_tail(btstack_linked_list_t * list, btstack_linked_item_t *item); +// pop (get + remove) first element +btstack_linked_item_t * btstack_linked_list_pop(btstack_linked_list_t * list); // remove item from list int btstack_linked_list_remove(btstack_linked_list_t * list, btstack_linked_item_t *item); +// get first element +btstack_linked_item_t * btstack_linked_list_get_first_item(btstack_linked_list_t * list); // find the last item in the list btstack_linked_item_t * btstack_linked_list_get_last_item(btstack_linked_list_t * list); diff --git a/test/linked_list/btstack_linked_list_test.c b/test/linked_list/btstack_linked_list_test.c index f8a27f3d5..6c2287982 100644 --- a/test/linked_list/btstack_linked_list_test.c +++ b/test/linked_list/btstack_linked_list_test.c @@ -32,6 +32,19 @@ TEST(LinkedList, CountAll){ CHECK_EQUAL(4, btstack_linked_list_count(&testList)); } +TEST(LinkedList, GetFirst){ + btstack_linked_item_t * item; + item = btstack_linked_list_get_first_item(&testList); + CHECK_EQUAL(item, &itemA); +} + +TEST(LinkedList, Pop){ + btstack_linked_item_t * item; + item = btstack_linked_list_pop(&testList); + CHECK_EQUAL(item, &itemA); + CHECK_EQUAL(3, btstack_linked_list_count(&testList)); +} + TEST(LinkedList, Iterator){ btstack_linked_list_iterator_t it; btstack_linked_list_iterator_init(&it, &testList);