mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-31 17:31:18 +01:00
Merge pull request #10574 from haukepetersen/add_bluetil_ad
net/ble: add generic advertisement data (AD) processing helper
This commit is contained in:
commit
dd55c792c5
@ -13,6 +13,9 @@ RIOTBASE ?= $(CURDIR)/../..
|
||||
# Include NimBLE
|
||||
USEPKG += nimble
|
||||
|
||||
# We also use the AD part of the BLE helper module
|
||||
USEMODULE += bluetil_ad
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
|
||||
@ -23,39 +23,26 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/bluetil/ad.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "host/ble_gatt.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
static const char device_name[] = "NimBLE on RIOT";
|
||||
static const char *device_name = "NimBLE on RIOT";
|
||||
static uint8_t own_addr_type;
|
||||
|
||||
|
||||
static void start_advertise(void);
|
||||
|
||||
static void put_ad(uint8_t ad_type, uint8_t ad_len, const void *ad, uint8_t *buf,
|
||||
uint8_t *len)
|
||||
{
|
||||
buf[(*len)++] = ad_len + 1;
|
||||
buf[(*len)++] = ad_type;
|
||||
|
||||
memcpy(&buf[*len], ad, ad_len);
|
||||
|
||||
*len += ad_len;
|
||||
}
|
||||
|
||||
static void update_ad(void)
|
||||
{
|
||||
uint8_t ad[BLE_HS_ADV_MAX_SZ];
|
||||
uint8_t ad_len = 0;
|
||||
uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len);
|
||||
put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(device_name), device_name, ad, &ad_len);
|
||||
|
||||
ble_gap_adv_set_data(ad, ad_len);
|
||||
uint8_t buf[BLE_HS_ADV_MAX_SZ];
|
||||
bluetil_ad_t ad;
|
||||
bluetil_ad_init_with_flags(&ad, buf, sizeof(buf), BLUETIL_AD_FLAGS_DEFAULT);
|
||||
bluetil_ad_add_name(&ad, device_name);
|
||||
ble_gap_adv_set_data(ad.buf, ad.pos);
|
||||
}
|
||||
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
|
||||
@ -133,6 +133,9 @@ endif
|
||||
ifneq (,$(filter cord_ep,$(USEMODULE)))
|
||||
DIRS += net/application_layer/cord/ep
|
||||
endif
|
||||
ifneq (,$(filter bluetil_%,$(USEMODULE)))
|
||||
DIRS += net/ble/bluetil
|
||||
endif
|
||||
|
||||
DIRS += $(dir $(wildcard $(addsuffix /Makefile, $(USEMODULE))))
|
||||
|
||||
|
||||
@ -46,6 +46,8 @@ extern "C" {
|
||||
#define BLE_CHAN_NUMOF (40U) /**< number of available channels */
|
||||
#define BLE_CHAN_ADV_NUMOF (3U) /**< number of advertising channels */
|
||||
#define BLE_CHAN_DAT_NUMOF (37U) /**< number of data channels */
|
||||
#define BLE_ADV_PDU_LEN (31U) /**< max size of legacy ADV packets */
|
||||
#define BLE_ADV_PDU_LEN_EXT (251U) /**< max size of extended ADV packets */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@ -325,6 +327,55 @@ extern "C" {
|
||||
#define BLE_ATT_FORMAT_U128 (0x02) /**< used in FIND_INFO_RESP */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name GAP advertisement data type values
|
||||
*
|
||||
* @see https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
|
||||
* @{
|
||||
*/
|
||||
#define BLE_GAP_AD_FLAGS (0x01)
|
||||
#define BLE_GAP_AD_UUID16_INCOMP (0x02)
|
||||
#define BLE_GAP_AD_UUID16_COMP (0x03)
|
||||
#define BLE_GAP_AD_UUID32_INCOMP (0x04)
|
||||
#define BLE_GAP_AD_UUID32_COMP (0x05)
|
||||
#define BLE_GAP_AD_UUID128_INCOMP (0x06)
|
||||
#define BLE_GAP_AD_UUID128_COMP (0x07)
|
||||
#define BLE_GAP_AD_NAME_SHORT (0x08)
|
||||
#define BLE_GAP_AD_NAME (0x09)
|
||||
#define BLE_GAP_AD_TX_POWER_LEVEL (0x0a)
|
||||
#define BLE_GAP_AD_CLASS_OF_DEVICE (0x0d)
|
||||
#define BLE_GAP_AD_PAIRING_HASH_192 (0x0e)
|
||||
#define BLE_GAP_AD_PAIRING_RAND_192 (0x0f)
|
||||
#define BLE_GAP_AD_DEVICE_ID (0x10)
|
||||
#define BLE_GAP_AD_SEC_MANAGER_TK_VAL (0x10)
|
||||
#define BLE_GAP_AD_SEC_MANAGER_OOB_FLAGS (0x11)
|
||||
#define BLE_GAP_AD_SLAVE_CON_INTERVAL (0x12)
|
||||
#define BLE_GAP_AD_LIST_SOL_UUID_16 (0x14)
|
||||
#define BLE_GAP_AD_LIST_SOL_UUID_128 (0x15)
|
||||
#define BLE_GAP_AD_SERVICE_DATA (0x16)
|
||||
#define BLE_GAP_AD_SERVICE_DATA_UUID16 (0x16)
|
||||
#define BLE_GAP_AD_ADDR_PUBLIC (0x17)
|
||||
#define BLE_GAP_AD_ADDR_RANDOM (0x18)
|
||||
#define BLE_GAP_AD_APPEARANCE (0x19)
|
||||
#define BLE_GAP_AD_ADV_INTERVAL (0x1a)
|
||||
#define BLE_GAP_AD_LE_DEVICE_ADDR (0x1b)
|
||||
#define BLE_GAP_AD_LE_ROLE (0x1c)
|
||||
#define BLE_GAP_AD_PAIRING_HASH_256 (0x1d)
|
||||
#define BLE_GAP_AD_PAIRING_RAND_256 (0x1e)
|
||||
#define BLE_GAP_AD_LIST_SOL_UUID_32 (0x1f)
|
||||
#define BLE_GAP_AD_SERVICE_DATA_32 (0x20)
|
||||
#define BLE_GAP_AD_SERVICE_DATA_128 (0x21)
|
||||
#define BLE_GAP_AD_LE_SEC_CON_CONF_VAL (0x22)
|
||||
#define BLE_GAP_AD_LE_SEC_CON_RAND_VAL (0x23)
|
||||
#define BLE_GAP_AD_URI (0x24)
|
||||
#define BLE_GAP_AD_INDOOR_POSITIONING (0x25)
|
||||
#define BLE_GAP_AD_TRANSPORT_DISC_DATA (0x26)
|
||||
#define BLE_GAP_AD_LE_SUP_FEATURES (0x27)
|
||||
#define BLE_GAP_AD_CHAN_MAP_UPDATE_IND (0x28)
|
||||
#define BLE_GAP_AD_3D_INFO_DATA (0x3d)
|
||||
#define BLE_GAP_AD_VENDOR (0xff)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Flags used in GAP advertisement packets
|
||||
* @{
|
||||
|
||||
195
sys/include/net/bluetil/ad.h
Normal file
195
sys/include/net/bluetil/ad.h
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_bluetil_ad BLE Advertising Data (AD) Processing
|
||||
* @ingroup net
|
||||
* @brief Generic BLE advertising and scan request data processing
|
||||
*
|
||||
* This module provides functionality for user friendly reading and writing of
|
||||
* BLE advertising and scan request buffers.
|
||||
*
|
||||
* This module is independent from any BLE stack.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Interface for the generic BLE advertising data processing module
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef NET_BLUETIL_AD_H
|
||||
#define NET_BLUETIL_AD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/ble.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Static initializer for the advertising data structure
|
||||
*/
|
||||
#define BLUETIL_AD_INIT(b,p,s) { .buf = b, .pos = p, .size = s }
|
||||
|
||||
/**
|
||||
* @brief Default flags to set when advertising BLE devices
|
||||
*/
|
||||
#define BLUETIL_AD_FLAGS_DEFAULT (BLE_GAP_DISCOVERABLE | \
|
||||
BLE_GAP_FLAG_BREDR_NOTSUP)
|
||||
|
||||
/**
|
||||
* @brief Return values used by the bluetil_ad module
|
||||
*/
|
||||
enum {
|
||||
BLUETIL_AD_OK = 0, /**< everything went as expected */
|
||||
BLUETIL_AD_NOTFOUND = -1, /**< entry not found */
|
||||
BLUETIL_AD_NOMEM = -2, /**< insufficient memory to write field */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Struct used for returning the contents of a selected field
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *data; /**< pointer a field's payload */
|
||||
size_t len; /**< length of the payload */
|
||||
} bluetil_ad_data_t;
|
||||
|
||||
/**
|
||||
* @brief Descriptor for a buffer containing advertising data
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *buf; /**< buffer containing the advertising data */
|
||||
size_t pos; /**< current write position in the buffer */
|
||||
size_t size; /**< overall length of the buffer */
|
||||
} bluetil_ad_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the given advertising data descriptor
|
||||
*
|
||||
* @param[out] ad advertising data descriptor
|
||||
* @param[in] buf buffer to point to
|
||||
* @param[in] pos current fill position of @p buf
|
||||
* @param[in] size size of @p buf
|
||||
*/
|
||||
void bluetil_ad_init(bluetil_ad_t *ad, void *buf, size_t pos, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Find a specific field in the given advertising data
|
||||
*
|
||||
* @param[in] ad advertising data descriptor
|
||||
* @param[in] type field type to look for
|
||||
* @param[out] data position and length of the field's payload
|
||||
*
|
||||
* @return BLUETIL_AD_OK if field was found
|
||||
* @return BLUETIL_AD_NOTFOUND if field was not found
|
||||
*/
|
||||
int bluetil_ad_find(const bluetil_ad_t *ad,
|
||||
uint8_t type, bluetil_ad_data_t *data);
|
||||
|
||||
/**
|
||||
* @brief Find the given field and copy its payload into a string
|
||||
*
|
||||
* The resulting string is `\0` terminated. If the resulting string is too large
|
||||
* to fit into the given buffer, it will be truncated to the maximum possible
|
||||
* size (but still including the `\0` at the end).
|
||||
*
|
||||
* @param[in] ad advertising data descriptor
|
||||
* @param[in] type field type to look for
|
||||
* @param[out] str resulting string is written to this buffer
|
||||
* @param[in] str_len maximum number of bytes to write to @p str, including
|
||||
* the `\0` character
|
||||
*
|
||||
* @return BLUETIL_AD_OK if the field was found and copied
|
||||
* @return BLUETIL_AD_NOTFOUND if the given field was not found
|
||||
*/
|
||||
int bluetil_ad_find_str(const bluetil_ad_t *ad, uint8_t type,
|
||||
char *str, size_t str_len);
|
||||
|
||||
/**
|
||||
* @brief Add a new field to the given advertising data
|
||||
*
|
||||
* @param[out] ad advertising data descriptor
|
||||
* @param[in] type field type to add
|
||||
* @param[in] data payload for the field
|
||||
* @param[in] data_len length of the payload in bytes
|
||||
*
|
||||
* @return BLUETIL_AD_OK if the new field was added
|
||||
* @return BLUETIL_AD_NOMEM if there is not enough space to write add field
|
||||
*/
|
||||
int bluetil_ad_add(bluetil_ad_t *ad, uint8_t type,
|
||||
const void *data, size_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Convenience function to add the "flags" field
|
||||
*
|
||||
* @param[out] ad advertising data descriptor
|
||||
* @param[in] flags flags to set
|
||||
*
|
||||
* @return BLUETIL_AD_OK if the flags field was added
|
||||
* @return BLUETIL_AD_NOMEM if there is not enough space to write add field
|
||||
*/
|
||||
static inline int bluetil_ad_add_flags(bluetil_ad_t *ad, uint8_t flags)
|
||||
{
|
||||
return bluetil_ad_add(ad, BLE_GAP_AD_FLAGS, &flags, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function to add the "full name" field
|
||||
*
|
||||
* While the given name must be `\0` terminated, the termination character is
|
||||
* not written to the advertising data.
|
||||
*
|
||||
* @param[out] ad advertising data descriptor
|
||||
* @param[in] name name to set
|
||||
*
|
||||
* @return BLUETIL_AD_OK if the name field was added
|
||||
* @return BLUETIL_AD_NOMEM if there is not enough space to add the name field
|
||||
*/
|
||||
static inline int bluetil_ad_add_name(bluetil_ad_t *ad, const char *name)
|
||||
{
|
||||
return bluetil_ad_add(ad, BLE_GAP_AD_NAME, name, strlen(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function for initializing the advertising data
|
||||
* descriptor and directly adding the flags field
|
||||
*
|
||||
* Most users will want to set the (mandatory) flags field right after
|
||||
* initializing the advertising context, so this function provides a small
|
||||
* shortcut.
|
||||
*
|
||||
* @param[out] ad advertising data descriptor
|
||||
* @param[out] buf buffer to write advertising data into
|
||||
* @param[in] buf_len size of @p buf in bytes
|
||||
* @param[in] flags flags to set, typically BLUETIL_AD_FLAGS_DEFAULT
|
||||
*
|
||||
* @return BLUETIL_AD_OK on successful initialization with flags field
|
||||
* @return BLUETIL_AD_NOMEM if given buffer is too small
|
||||
*/
|
||||
static inline int bluetil_ad_init_with_flags(bluetil_ad_t *ad,
|
||||
void *buf, size_t buf_len,
|
||||
uint8_t flags)
|
||||
{
|
||||
bluetil_ad_init(ad, buf, 0, buf_len);
|
||||
return bluetil_ad_add_flags(ad, flags);
|
||||
}
|
||||
|
||||
/* add more convenience functions on demand... */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_BLUETIL_AD_H */
|
||||
/** @} */
|
||||
3
sys/net/ble/bluetil/Makefile
Normal file
3
sys/net/ble/bluetil/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
DIRS += $(filter bluetil_%,$(USEMODULE))
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
1
sys/net/ble/bluetil/bluetil_ad/Makefile
Normal file
1
sys/net/ble/bluetil/bluetil_ad/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
92
sys/net/ble/bluetil/bluetil_ad/bluetil_ad.c
Normal file
92
sys/net/ble/bluetil/bluetil_ad/bluetil_ad.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_bluetil_ad
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of the generic BLE advertising data processing
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "net/bluetil/ad.h"
|
||||
|
||||
#define POS_TYPE (1U)
|
||||
#define POS_DATA (2U)
|
||||
|
||||
void bluetil_ad_init(bluetil_ad_t *ad, void *buf, size_t pos, size_t size)
|
||||
{
|
||||
assert(ad);
|
||||
assert(buf);
|
||||
|
||||
ad->buf = buf;
|
||||
ad->pos = pos;
|
||||
ad->size = size;
|
||||
}
|
||||
|
||||
int bluetil_ad_find(const bluetil_ad_t *ad, uint8_t type,
|
||||
bluetil_ad_data_t *data)
|
||||
{
|
||||
assert(ad);
|
||||
assert(data);
|
||||
|
||||
unsigned pos = 0;
|
||||
|
||||
while ((pos + POS_TYPE) < ad->pos) {
|
||||
uint8_t len = ad->buf[pos];
|
||||
|
||||
if (ad->buf[pos + POS_TYPE] == type) {
|
||||
data->data = ad->buf + pos + POS_DATA;
|
||||
data->len = len - 1; /* take away the type field */
|
||||
return BLUETIL_AD_OK;
|
||||
}
|
||||
|
||||
pos += (len + 1);
|
||||
}
|
||||
|
||||
return BLUETIL_AD_NOTFOUND;
|
||||
}
|
||||
|
||||
int bluetil_ad_find_str(const bluetil_ad_t *ad, uint8_t type,
|
||||
char *str, size_t str_len)
|
||||
{
|
||||
bluetil_ad_data_t f;
|
||||
int res = bluetil_ad_find(ad, type, &f);
|
||||
if (res != BLUETIL_AD_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t len = (f.len >= str_len) ? (str_len - 1) : f.len;
|
||||
memcpy(str, f.data, len);
|
||||
str[len] = '\0';
|
||||
|
||||
return BLUETIL_AD_OK;
|
||||
}
|
||||
|
||||
int bluetil_ad_add(bluetil_ad_t *ad, uint8_t field_type,
|
||||
const void *data, size_t data_len)
|
||||
{
|
||||
assert(ad);
|
||||
|
||||
if ((ad->pos + 2 + data_len) > ad->size) {
|
||||
return BLUETIL_AD_NOMEM;
|
||||
}
|
||||
ad->buf[ad->pos++] = data_len + 1;
|
||||
ad->buf[ad->pos++] = field_type;
|
||||
memcpy(&ad->buf[ad->pos], data, data_len);
|
||||
ad->pos += data_len;
|
||||
|
||||
return BLUETIL_AD_OK;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user