From 87bf819c9564da275d5f45636c77f07c64da7674 Mon Sep 17 00:00:00 2001
From: Milanka Ringwald <mila@ringwald.ch>
Date: Fri, 3 Jul 2015 17:13:55 +0200
Subject: [PATCH] added example how to parse advertisements

---
 example/embedded/Makefile.inc            |   5 +
 example/embedded/gap_le_advertisements.c | 244 +++++++++++++++++++++++
 2 files changed, 249 insertions(+)
 create mode 100644 example/embedded/gap_le_advertisements.c

diff --git a/example/embedded/Makefile.inc b/example/embedded/Makefile.inc
index 2575f132e..749a5b80b 100644
--- a/example/embedded/Makefile.inc
+++ b/example/embedded/Makefile.inc
@@ -72,6 +72,7 @@ EXAMPLES = 					\
 	spp_and_le_counter 		\
 	spp_counter 			\
 	spp_streamer			\
+    gap_le_advertisements   \
 
 EXAMPLES_USING_LE =			\
 	ancs_client 			\
@@ -80,6 +81,7 @@ EXAMPLES_USING_LE =			\
 	le_counter              \
 	le_streamer				\
 	spp_and_le_counter	    \
+    gap_le_advertisements   \
 
 # .o for .c
 CORE_OBJ    = $(CORE:.c=.o)
@@ -163,6 +165,9 @@ led_counter: ${CORE_OBJ} ${COMMON_OBJ} led_counter.c
 ble_client: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${GATT_CLIENT_OBJ} ${SM_REAL} ble_client.c
 	${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
 
+gap_le_advertisements: ${CORE_OBJ} ${COMMON_OBJ} ad_parser.c gap_le_advertisements.c
+	${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
+
 
 clean:
 	rm -f ${EXAMPLES}
diff --git a/example/embedded/gap_le_advertisements.c b/example/embedded/gap_le_advertisements.c
new file mode 100644
index 000000000..253527346
--- /dev/null
+++ b/example/embedded/gap_le_advertisements.c
@@ -0,0 +1,244 @@
+/*
+ * 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(gap_le_advertisements): GAP LE Advertisements Dumper
+ *
+ * @text This example shows how to scan for advertisements and how to parse them.
+ * 
+ */
+ // *****************************************************************************
+
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <btstack/hci_cmds.h>
+
+#include "btstack_memory.h"
+#include "hci.h"
+#include "ad_parser.h"
+
+
+static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+static void gap_le_advertisements_setup(){
+    hci_register_packet_handler(handle_hci_event);
+}
+
+static char * ad_types[] = {
+    "", 
+    "Flags",
+    "Incomplete List of 16-bit Service Class UUIDs",
+    "Complete List of 16-bit Service Class UUIDs",
+    "Incomplete List of 32-bit Service Class UUIDs",
+    "Complete List of 32-bit Service Class UUIDs",
+    "Incomplete List of 128-bit Service Class UUIDs",
+    "Complete List of 128-bit Service Class UUIDs",
+    "Shortened Local Name",
+    "Complete Local Name",
+    "Tx Power Level",
+    "", 
+    "", 
+    "Class of Device",
+    "Simple Pairing Hash C",
+    "Simple Pairing Randomizer R",
+    "Device ID",
+    "Security Manager TK Value",
+    "Slave Connection Interval Range",
+    "",
+    "List of 16-bit Service Solicitation UUIDs",
+    "List of 128-bit Service Solicitation UUIDs",
+    "Service Data",
+    "Public Target Address",
+    "Random Target Address",
+    "Appearance",
+    "Advertising Interval"
+};
+
+static char * flags[] = {
+    "LE Limited Discoverable Mode",
+    "LE General Discoverable Mode",
+    "BR/EDR Not Supported",
+    "Simultaneous LE and BR/EDR to Same Device Capable (Controller)",
+    "Simultaneous LE and BR/EDR to Same Device Capable (Host)",
+    "Reserved",
+    "Reserved",
+    "Reserved"
+};
+
+void dump_advertisement_data(uint8_t * adv_data, uint8_t adv_size){
+    ad_context_t context;
+    
+    for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
+        uint8_t data_type = ad_iterator_get_data_type(&context);
+        uint8_t size      = ad_iterator_get_data_len(&context);
+        uint8_t * data    = ad_iterator_get_data(&context);
+        
+        if (data_type > 0 && data_type < 0x1B){
+            printf("%s: ", ad_types[data_type]);
+        } 
+        int i;
+        // Assigned Numbers GAP
+        switch (data_type){
+            case 0x01: // Flags
+                // show only first octet, ignore rest
+                printf("\n");
+                for (i=0; i<8;i++){
+                    if (data[0] & (1<<i)){
+                        printf("Flags bit nr. %d : %s\n", i, flags[i]);
+                    }
+                }
+                break;
+            case 0x02: // Incomplete List of 16-bit Service Class UUIDs
+            case 0x03: // Complete List of 16-bit Service Class UUIDs
+            case 0x14: // List of 16-bit Service Solicitation UUIDs
+                for (i=0; i<size;i+=2){
+                    printf("%02X ", READ_BT_16(data, i));
+                }
+                printf("\n");
+                break;
+            case 0x04: // Incomplete List of 32-bit Service Class UUIDs
+            case 0x05: // Complete List of 32-bit Service Class UUIDs
+                for (i=0; i<size;i+=4){
+                    printf("%04X ", READ_BT_32(data, i));
+                }
+                printf("\n");
+                break;
+            case 0x06: // Incomplete List of 128-bit Service Class UUIDs
+            case 0x07: // Complete List of 128-bit Service Class UUIDs
+            case 0x15: // List of 128-bit Service Solicitation UUIDs
+                printUUID128(data);
+                printf("\n");
+                break;
+            case 0x08: // Shortened Local Name
+            case 0x09: // Complete Local Name
+                for (i=0; i<size;i++){
+                    printf("%c", (char)(data[i]));
+                }
+                printf("\n");
+                break;
+            case 0x0A: // Tx Power Level 
+                printf("%d dBm\n", *(int8_t*)data);
+                break;
+            case 0x12: // Slave Connection Interval Range 
+                printf("\n");
+                printf("Minimum Connection Interval %u ms\n", READ_BT_16(data, 0) * 5/4);
+                printf("Maximum Connection Interval %u ms\n", READ_BT_16(data, 2) * 5/4);
+                break;
+            case 0x16: // Service Data 
+                printf_hexdump(data, size);
+                break;
+            case 0x17: // Public Target Address
+            case 0x18: // Random Target Address
+                print_bd_addr(data);
+                printf("\n");
+                break;
+            case 0x19: // Appearance 
+                // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
+                printf("%02X\n", READ_BT_16(data, 0) );
+                break;
+            case 0x1A: // Advertising Interval 
+                printf("%u ms\n", READ_BT_16(data, 0) * 5/8 );
+                break;
+            case 0x3D: // 3D Information Data 
+                printf_hexdump(data, size);
+                break;
+            case 0xFF: // Manufacturer Specific Data 
+                break;
+            case 0x0D: // Class of Device (3B)
+            case 0x0E: // Simple Pairing Hash C (16B)
+            case 0x0F: // Simple Pairing Randomizer R (16B) 
+            case 0x10: // Device ID 
+            case 0x11: // Security Manager TK Value (16B)
+            default:
+                printf("Unknown Advertising Data Type\n"); 
+                break;
+        }
+        
+    }
+}
+
+static void handle_hci_event(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    if (packet_type != HCI_EVENT_PACKET) return;
+    
+    switch (packet[0]) {
+        case BTSTACK_EVENT_STATE:
+            // BTstack activated, get started
+            if (packet[2] == HCI_STATE_WORKING) {
+                printf("BTstack activated, start scaning!\n");
+                le_central_set_scan_parameters(0,0x0030, 0x0030);
+                le_central_start_scan(); 
+            }
+            break;
+        case GAP_LE_ADVERTISING_REPORT:{
+            int pos = 2;
+            uint8_t event_type = packet[pos++];
+            uint8_t address_type = packet[pos++];
+            bd_addr_t address;
+            memcpy(address, &packet[pos], 6);
+            pos += 6;
+            uint8_t rssi = packet[pos++];
+            uint8_t length = packet[pos++];
+            uint8_t * data = &packet[pos];
+            
+            printf("\n\nAdvertisement event: evt-type %u, addr-type %u, addr %s, rssi %u, length adv %u, data: ", event_type,
+               address_type, bd_addr_to_str(address), rssi, length);
+            printf_hexdump(data, length);
+            dump_advertisement_data(data, length);
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+int btstack_main(void);
+int btstack_main(void)
+{
+    gap_le_advertisements_setup();
+
+    // turn on!
+    hci_power_control(HCI_POWER_ON);
+        
+    return 0;
+}
+
+/* EXAMPLE_END */
\ No newline at end of file