implement advertising or scan data parser

This commit is contained in:
mila@ringwald.ch 2013-11-09 23:48:36 +00:00
parent 45c3b63f47
commit 60c84a4425
6 changed files with 339 additions and 88 deletions

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2011-2013 by Matthias Ringwald
*
* 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. This software may not be used in a commercial product
* without an explicit license granted by the copyright holder.
*
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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.
*
*/
//*****************************************************************************
//
// Advertising Data Parser
//
//*****************************************************************************
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ad_parser.h"
void ad_iterator_init(ad_context_t *context, uint8_t ad_len, uint8_t * ad_data){
context->data = ad_data;
context->length = ad_len;
context->offset = 0;
}
int ad_iterator_has_more(ad_context_t * context){
return context->offset < context->length;
}
void ad_iterator_next(ad_context_t * context){
uint8_t chunk_len = context->data[context->offset];
context->offset += 1 + chunk_len;
}
uint8_t ad_iterator_get_data_len(ad_context_t * context){
return context->data[context->offset] - 1;
}
uint8_t ad_iterator_get_data_type(ad_context_t * context){
return context->data[context->offset + 1];
}
uint8_t * ad_iterator_get_data(ad_context_t * context){
return &context->data[context->offset + 2];
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2011-2013 by Matthias Ringwald
*
* 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. This software may not be used in a commercial product
* without an explicit license granted by the copyright holder.
*
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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.
*
*/
//*****************************************************************************
//
// Advertising Data Parser
//
//*****************************************************************************
#pragma once
#include "config.h"
#include <btstack/utils.h>
#if defined __cplusplus
extern "C" {
#endif
typedef struct ad_context {
uint8_t * data;
uint8_t offset;
uint8_t length;
} ad_context_t;
// Advertising or Scan Response data iterator
void ad_iterator_init(ad_context_t *context, uint8_t ad_len, uint8_t * ad_data);
int ad_iterator_has_more(ad_context_t * context);
void ad_iterator_next(ad_context_t * context);
// Access functions
uint8_t ad_iterator_get_data_type(ad_context_t * context);
uint8_t ad_iterator_get_data_len(ad_context_t * context);
uint8_t * ad_iterator_get_data(ad_context_t * context);
// convenience function on complete advertisements
int ad_data_contains_uuid16(uint8_t ad_len, uint8_t * ad_data, uint16_t uuid);
int ad_data_contains_uuid128(uint8_t ad_len, uint8_t * ad_data, uint8_t * uuid128);
#if defined __cplusplus
}
#endif

View File

@ -46,7 +46,7 @@
#include <string.h>
#include <btstack/run_loop.h>
#include "config.h"
#include "ble_client.h"
#include "debug.h"
#include "btstack_memory.h"
@ -56,90 +56,17 @@
#include "l2cap.h"
#include "att.h"
// API
typedef struct gatt_client_event {
uint8_t type;
} gatt_client_event_t;
typedef struct ad_event {
uint8_t type;
uint8_t event_type;
uint8_t address_type;
bd_addr_t address;
uint8_t rssi;
uint8_t length;
uint8_t * data;
} ad_event_t;
#include "ad_parser.h"
void (*gatt_client_callback)(gatt_client_event_t * event);
void gatt_client_init();
void gatt_client_start_scan();
// creates one event per found peripheral device
// EVENT: type (8), addr_type (8), addr(48), rssi(8), ad_len(8), ad_data(ad_len*8)
void gatt_client_stop_scan();
/*
typedef struct service_uuid{
uint8_t lenght;
uint8_t * uuid;
} service_uuid_t;
typedef struct peripheral{
} peripheral_t;
// Advertising Data Parser
typedef struct ad_context {
uint8_t * data;
uint8_t offset;
uint8_t length;
} ad_context_t;
// iterator
void ad_init(ad_context_t *context, uint8_t ad_len, uint8_t * ad_data);
int ad_has_more(ad_context_t * context);
void ad_next(ad_context_t * context);
// access functions
uint8_t ad_get_data_type(ad_context_t * context);
uint8_t ad_get_data_len(ad_context_t * context);
uint8_t * ad_get_data(ad_context_t * context);
// convenience function on complete advertisements
int ad_data_contains_uuid16(uint8_t ad_len, uint8_t * ad_data, uint16_t uuid);
int ad_data_contains_uuid128(uint8_t ad_len, uint8_t * ad_data, uint8_t * uuid128);
// example use of Advertisment Data Parser
void test_ad_parser(){
ad_context_t context;
for (ad_init(&context, len, data) ; ad_has_more(&context) ; ad_next(&context)){
uint8_t data_type = ad_get_data_type(&context);
uint8_t data_len = ad_get_data_len(&context);
uint8_t * data = ad_get_data(&context);
static void hexdump2(void *data, int size){
int i;
for (i=0; i<size;i++){
printf("%02X ", ((uint8_t *)data)[i]);
}
printf("\n");
}
// GATT Client API
void gatt_client_register_handler( btstack_packet_handler_t handler);
uint16_t gatt_client_connect(bt_addr_t *dev);
void gatt_client_cancel_connect(peripheral_id peripheral);
void get_services_for_peripheral(peripheral_id peripheral);
// EVENT: type (8), peripheral_id (16), service_id
void get_characteristics_for_service(peripheral_id, service_id);
// EVENT: type (8), peripheral_id (16), service_id (16), ...
*/
// END API
// gatt client state
static uint8_t requested_scan_state = 0;
static uint8_t scan_state = 0;
@ -174,14 +101,6 @@ void gatt_client_stop_scan(){
}
static void hexdump2(void *data, int size){
int i;
for (i=0; i<size;i++){
printf("%02X ", ((uint8_t *)data)[i]);
}
printf("\n");
}
static void dump_ad_event(ad_event_t e){
printf("evt-type %u, addr-type %u, addr %s, rssi %u, length adv %u, data: ", e.event_type,
e.address_type, bd_addr_to_str(e.address), e.rssi, e.length);

108
example/libusb/ble_client.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2011-2013 by Matthias Ringwald
*
* 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. This software may not be used in a commercial product
* without an explicit license granted by the copyright holder.
*
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD 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.
*
*/
//*****************************************************************************
//
// BLE Client
//
//*****************************************************************************
// NOTE: Supports only a single connection
#pragma once
#include "config.h"
#include <btstack/utils.h>
#if defined __cplusplus
extern "C" {
#endif
typedef struct gatt_client_event {
uint8_t type;
} gatt_client_event_t;
typedef struct ad_event {
uint8_t type;
uint8_t event_type;
uint8_t address_type;
bd_addr_t address;
uint8_t rssi;
uint8_t length;
uint8_t * data;
} ad_event_t;
void (*gatt_client_callback)(gatt_client_event_t * event);
void gatt_client_init();
void gatt_client_start_scan();
// creates one event per found peripheral device
// EVENT: type (8), addr_type (8), addr(48), rssi(8), ad_len(8), ad_data(ad_len*8)
void gatt_client_stop_scan();
/*
typedef struct service_uuid{
uint8_t lenght;
uint8_t * uuid;
} service_uuid_t;
typedef struct peripheral{
} peripheral_t;
// GATT Client API
void gatt_client_register_handler( btstack_packet_handler_t handler);
uint16_t gatt_client_connect(bt_addr_t *dev);
void gatt_client_cancel_connect(peripheral_id peripheral);
void get_services_for_peripheral(peripheral_id peripheral);
// EVENT: type (8), peripheral_id (16), service_id
void get_characteristics_for_service(peripheral_id, service_id);
// EVENT: type (8), peripheral_id (16), service_id (16), ...
*/
#if defined __cplusplus
}
#endif

25
test/ble_client/Makefile Normal file
View File

@ -0,0 +1,25 @@
CC = g++
# Requirements: http://www.cpputest.org/ should be placed in btstack/test
BTSTACK_ROOT = ../..
CPPUTEST_HOME = ${BTSTACK_ROOT}/test/cpputest
CFLAGS = -g -Wall -I. -I${BTSTACK_ROOT}/example/libusb -I${BTSTACK_ROOT}/include -I$(CPPUTEST_HOME)/include
LDFLAGS += -L$(CPPUTEST_HOME) -lCppUTest -lCppUTestExt
COMMON = \
${BTSTACK_ROOT}/example/libusb/ad_parser.c \
COMMON_OBJ = $(COMMON:.c=.o)
all: ad_parser
ad_parser: ${CORE_OBJ} ${COMMON_OBJ} advertising_data_parser.c
${CC} ${CORE_OBJ} ${COMMON_OBJ} advertising_data_parser.c ${CFLAGS} ${LDFLAGS} -o $@
clean:
rm -f ad_parser
rm -f *.o ${BTSTACK_ROOT}/src/*.o
rm -rf *.dSYM

View File

@ -0,0 +1,53 @@
//*****************************************************************************
//
// test rfcomm query tests
//
//*****************************************************************************
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ad_parser.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
static uint8_t ad_data[] = {0x02, 0x01, 0x05, 0x03, 0x02, 0xF0, 0xFF};
TEST_GROUP(ADParser){
};
TEST(ADParser, Test){
ad_context_t context;
uint8_t expected_len[] = {1, 2};
uint8_t expected_type[] = {0x01, 0x02};
uint8_t expected_data[][2] = {{0x05, 0x00}, {0xF0, 0xFF}};
int i = 0;
uint8_t ad_len = sizeof(ad_data);
for (ad_iterator_init(&context, ad_len, ad_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
uint8_t data_type = ad_iterator_get_data_type(&context);
uint8_t data_len = ad_iterator_get_data_len(&context);
uint8_t * data = ad_iterator_get_data(&context);
CHECK_EQUAL(expected_len[i], data_len);
CHECK_EQUAL(expected_type[i], data_type);
int j;
for (j = 0; j < data_len; j++){
CHECK_EQUAL(expected_data[i][j], data[j]);
}
i++;
}
}
int main (int argc, const char * argv[]){
return CommandLineTestRunner::RunAllTests(argc, argv);
}