diff --git a/docs/manual/update_listings.py b/docs/manual/update_listings.py old mode 100644 new mode 100755 index f378fd8ee..f8a63c146 --- a/docs/manual/update_listings.py +++ b/docs/manual/update_listings.py @@ -60,14 +60,17 @@ msp_folder = "../../platforms/msp-exp430f5438-cc2564b/example/" embedded_folder = "../../example/embedded/" # Example group title: [folder, example file, section title] list_of_examples = { - "UART" : [[embedded_folder, "led_counter", "UART and timer interrupt without Bluetooth"]], - "GAP" : [[embedded_folder, "gap_inquiry", "GAP Inquiry Example"]], - "SPP Server" : [[embedded_folder, "spp_counter", "SPP Server - Heartbeat Counter over RFCOMM"], - [embedded_folder, "spp_flowcontrol", "SPP Server - Flow Control"]], - "Low Energy" :[[embedded_folder, "gatt_browser", "GATT Client - Discovering primary services and their characteristics"], - [embedded_folder, "ble_peripheral", "LE Peripheral"]], - "Dual Mode " :[[embedded_folder, "spp_and_le_counter", "Dual mode example"]], - "SDP BNEP Query" :[[embedded_folder, "sdp_bnep_query", "SDP BNEP Query"]] + "Hello World" : [[embedded_folder, "led_counter", "UART and timer interrupt without Bluetooth"]], + "GAP" : [[embedded_folder, "gap_inquiry", "GAP Inquiry Example"]], + "SDP Queries" :[[embedded_folder, "sdp_general_query", "SDP General Query"], + # [embedded_folder, "sdp_bnep_query", "SDP BNEP Query"] + ], + "SPP Server" : [[embedded_folder, "spp_counter", "SPP Server - Heartbeat Counter over RFCOMM"], + [embedded_folder, "spp_flowcontrol", "SPP Server - Flow Control"]], + "BNEP/PAN" : [[embedded_folder, "panu_demo", "PANU example"]], + "Low Energy" : [[embedded_folder, "gatt_browser", "GATT Client - Discovering primary services and their characteristics"], + [embedded_folder, "le_counter", "LE Peripheral - Counter example"]], + "Dual Mode " : [[embedded_folder, "spp_and_le_counter", "Dual mode example: Combined SPP Counter + LE Counter "]], } class State: diff --git a/example/embedded/Makefile.inc b/example/embedded/Makefile.inc index 7c7888b80..2f5f2328f 100644 --- a/example/embedded/Makefile.inc +++ b/example/embedded/Makefile.inc @@ -62,25 +62,26 @@ EXAMPLES = \ gap_inquiry_and_bond \ gatt_battery_query \ gatt_browser \ + le_counter \ + led_counter \ sdp_bnep_query \ sdp_general_query \ sdp_rfcomm_query \ spp_and_le_counter \ spp_counter \ spp_streamer \ - led_counter \ EXAMPLES_USING_LE = \ ancs_client \ ble_central_test \ - ble_peripheral \ - ble_peripheral_sm_minimal \ + ble_peripheral_test \ gatt_battery_query \ gatt_browser \ + led_counter \ spp_and_le_counter \ # requires termios / command line support -EXAMPLES_CLI = ble_peripheral ble_peripheral_sm_minimal ble_central_test l2cap_test ancs_client classic_test bnep_test hsp_ag_test hsp_hs_test +EXAMPLES_CLI = ble_peripheral_test ble_central_test l2cap_test ancs_client classic_test bnep_test hsp_ag_test hsp_hs_test # .o for .c CORE_OBJ = $(CORE:.c=.o) @@ -104,6 +105,8 @@ ancs_client.h: ancs_client.gatt python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ spp_and_le_counter.h: spp_and_le_counter.gatt python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ +le_counter.h: le_counter.gatt + python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ # examples sdp_rfcomm_query: ${CORE_OBJ} ${COMMON_OBJ} ${PAN_OBJ} ${SDP_CLIENT} sdp_rfcomm_query.c @@ -118,6 +121,9 @@ sdp_bnep_query: ${CORE_OBJ} ${COMMON_OBJ} ${SDP_CLIENT} sdp_bnep_query.c spp_counter: ${CORE_OBJ} ${COMMON_OBJ} spp_counter.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ +le_counter: le_counter.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} le_counter.c + ${CC} $(filter-out le_counter.h,$^) ${CFLAGS} ${LDFLAGS} -o $@ + spp_and_le_counter: spp_and_le_counter.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} spp_and_le_counter.c ${CC} $(filter-out spp_and_le_counter.h,$^) ${CFLAGS} ${LDFLAGS} -o $@ @@ -150,10 +156,7 @@ ancs_client: ancs_client.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OB # CLI Examples -ble_peripheral: profile.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} ble_peripheral.o - ${CC} $(filter-out profile.h,$^) ${CFLAGS} ${LDFLAGS} -o $@ - -ble_peripheral_sm_minimal: profile.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_MINIMAL_OBJ} ble_peripheral.c +ble_peripheral_test: profile.h ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_SERVER_OBJ} ${SM_REAL_OBJ} ble_peripheral.o ${CC} $(filter-out profile.h,$^) ${CFLAGS} ${LDFLAGS} -o $@ ble_central_test: ${CORE_OBJ} ${COMMON_OBJ} ${SM_REAL_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ble_central_test.c diff --git a/example/embedded/ble_peripheral.c b/example/embedded/ble_peripheral_test.c similarity index 100% rename from example/embedded/ble_peripheral.c rename to example/embedded/ble_peripheral_test.c diff --git a/example/embedded/gatt_browser.c b/example/embedded/gatt_browser.c index 4e8292dd1..0266a8689 100644 --- a/example/embedded/gatt_browser.c +++ b/example/embedded/gatt_browser.c @@ -90,7 +90,6 @@ uint16_t gc_handle; static le_service_t services[40]; static int service_count = 0; static int service_index = 0; -static gc_state_t state = TC_IDLE; /* @section Setting up GATT client @@ -119,7 +118,7 @@ static uint16_t gc_id; // Handles connect, disconnect, and advertising report events, // starts the GATT client, and sends the first query. -void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); +static void handle_hci_event(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); // Handles GATT client query results, sends queries and the // GAP disconnect command when the querying is done. diff --git a/example/embedded/le_counter.c b/example/embedded/le_counter.c new file mode 100644 index 000000000..70b0f25c8 --- /dev/null +++ b/example/embedded/le_counter.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2014 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 + * + */ + +// ***************************************************************************** +/* EXAMPLE_START(le_counter): Dual mode example + * + */ +// ***************************************************************************** + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "btstack-config.h" + +#include <btstack/run_loop.h> +#include <btstack/sdp_util.h> + +#include "debug.h" +#include "btstack_memory.h" +#include "hci.h" +#include "hci_dump.h" + +#include "l2cap.h" + +#include "le_counter.h" + +#include "att.h" +#include "att_server.h" +#include "le_device_db.h" +#include "gap_le.h" +#include "sm.h" + +#define HEARTBEAT_PERIOD_MS 1000 + +static int le_notification_enabled; + +// THE Couner +static timer_source_t heartbeat; +static int counter = 0; +static char counter_string[30]; +static int counter_string_len; + +const uint8_t adv_data[] = { + // Flags general discoverable + 0x02, 0x01, 0x02, + // Name + 0x0b, 0x09, 'L', 'E', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r', +}; +uint8_t adv_data_len = sizeof(adv_data); + +enum { + SET_ADVERTISEMENT_PARAMS = 1 << 0, + SET_ADVERTISEMENT_DATA = 1 << 1, + ENABLE_ADVERTISEMENTS = 1 << 2, +}; +static uint16_t todos = 0; + + +static void gap_run(){ + + if (!hci_can_send_command_packet_now()) return; + + if (todos & SET_ADVERTISEMENT_DATA){ + printf("GAP_RUN: set advertisement data\n"); + todos &= ~SET_ADVERTISEMENT_DATA; + hci_send_cmd(&hci_le_set_advertising_data, adv_data_len, adv_data); + return; + } + + if (todos & SET_ADVERTISEMENT_PARAMS){ + todos &= ~SET_ADVERTISEMENT_PARAMS; + uint8_t adv_type = 0; // default + bd_addr_t null_addr; + memset(null_addr, 0, 6); + uint16_t adv_int_min = 0x0030; + uint16_t adv_int_max = 0x0030; + hci_send_cmd(&hci_le_set_advertising_parameters, adv_int_min, adv_int_max, adv_type, 0, 0, &null_addr, 0x07, 0x00); + return; + } + + if (todos & ENABLE_ADVERTISEMENTS){ + printf("GAP_RUN: enable advertisements\n"); + todos &= ~ENABLE_ADVERTISEMENTS; + hci_send_cmd(&hci_le_set_advertise_enable, 1); + return; + } +} + +static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + switch (packet_type) { + case HCI_EVENT_PACKET: + switch (packet[0]) { + + case BTSTACK_EVENT_STATE: + // bt stack activated, get started - set local name + if (packet[2] == HCI_STATE_WORKING) { + todos = SET_ADVERTISEMENT_PARAMS | SET_ADVERTISEMENT_DATA | ENABLE_ADVERTISEMENTS; + gap_run(); + } + break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + todos = ENABLE_ADVERTISEMENTS; + le_notification_enabled = 0; + gap_run(); + break; + + default: + break; + } + break; + + default: + break; + } + gap_run(); +} + +// ATT Client Read Callback for Dynamic Data +// - if buffer == NULL, don't copy data, just return size of value +// - if buffer != NULL, copy data and return number bytes copied +// @param offset defines start of attribute value +static uint16_t att_read_callback(uint16_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ + if (att_handle == ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE){ + if (buffer){ + memcpy(buffer, &counter_string[offset], counter_string_len - offset); + } + return counter_string_len - offset; + } + return 0; +} + +// write requests +static int att_write_callback(uint16_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ + // printf("WRITE Callback, handle %04x, mode %u, offset %u, data: ", handle, transaction_mode, offset); + // printf_hexdump(buffer, buffer_size); + if (att_handle != ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE) return 0; + le_notification_enabled = READ_BT_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION; + return 0; +} + +static void heartbeat_handler(struct timer *ts){ + counter++; + counter_string_len = sprintf(counter_string, "BTstack counter %04u\n", counter); + puts("%s", counter_string); + + if (le_notification_enabled) { + att_server_notify(ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t*) counter_string, counter_string_len); + } + run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS); + run_loop_add_timer(ts); +} + +// main == setup +int btstack_main(void); +int btstack_main(void) +{ + l2cap_init(); + l2cap_register_packet_handler(packet_handler); + + // setup le device db + le_device_db_init(); + + // setup SM: Display only + sm_init(); + + // setup ATT server + att_server_init(profile_data, att_read_callback, att_write_callback); + att_dump_attributes(); + // set one-shot timer + heartbeat.process = &heartbeat_handler; + run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); + run_loop_add_timer(&heartbeat); + + // turn on! + hci_power_control(HCI_POWER_ON); + + return 0; +} +/* EXAMPLE_END */ diff --git a/example/embedded/le_counter.gatt b/example/embedded/le_counter.gatt new file mode 100644 index 000000000..fb0e8a549 --- /dev/null +++ b/example/embedded/le_counter.gatt @@ -0,0 +1,12 @@ +PRIMARY_SERVICE, GAP_SERVICE +CHARACTERISTIC, GAP_DEVICE_NAME, READ, "SPP+LE Counter" + +PRIMARY_SERVICE, GATT_SERVICE +CHARACTERISTIC, GATT_SERVICE_CHANGED, READ, + +// Counter Service +PRIMARY_SERVICE, 0000FF10-0000-1000-8000-00805F9B34FB +// Counter Characteristic, with read and notify +CHARACTERISTIC, 0000FF11-0000-1000-8000-00805F9B34FB, READ | NOTIFY | DYNAMIC, + + diff --git a/example/embedded/led_counter.c b/example/embedded/led_counter.c index 1bd10d706..2ca985c5c 100644 --- a/example/embedded/led_counter.c +++ b/example/embedded/led_counter.c @@ -36,12 +36,11 @@ */ // ***************************************************************************** -/* EXAMPLE_START(led_counter): UART and timer interrupt without Bluetooth +/* EXAMPLE_START(led_counter): Hello World: blinking LED without Bluetooth * * @text The example uses the BTstack run loop to blink an LED. - * The example demonstrates how to setup hardware, initialize BTstack without - * Bluetooth, provide a periodic timer to toggle an LED and print number of - * toggles as a minimal BTstack test. + * The example demonstrates how to provide a periodic timer to toggle an LED + * and send debug messages to the console as a minimal BTstack test. */ // ***************************************************************************** @@ -58,11 +57,6 @@ static int counter = 0; static timer_source_t heartbeat; -static void run_loop_register_timer(timer_source_t *timer, uint16_t period){ - run_loop_set_timer(timer, period); - run_loop_add_timer(timer); -} - /* @section Periodic Timer Setup * * @text As timers in BTstack are single shot, @@ -82,7 +76,8 @@ static void heartbeat_handler(timer_source_t *ts){ hal_led_toggle(); // re-register timer - run_loop_register_timer(ts, HEARTBEAT_PERIOD_MS); + run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); + run_loop_add_timer(&heartbeat); } /* LISTING_END */ @@ -97,10 +92,13 @@ static void heartbeat_handler(timer_source_t *ts){ /* LISTING_START(MainConfiguration): Setup heartbeat timer */ int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ + // set one-shot timer heartbeat.process = &heartbeat_handler; - run_loop_register_timer(&heartbeat, HEARTBEAT_PERIOD_MS); - printf("Run...\n\r"); + run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); + run_loop_add_timer(&heartbeat); + + printf("Running...\n\r"); return 0; } /* LISTING_END */