blob: 3317a718799578b546da5c192724eae409b86796 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <string.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
__BEGIN_CDECLS;
// BT SIG Base UUID for all 16/32 assigned UUID values.
//
// "00000000-0000-1000-8000-00805F9B34FB"
//
// (see Core Spec v5.0, Vol 3, Part B, Section 2.5.1)
#define BT_GATT_BASE_UUID \
{ \
0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00 \
}
#define __BT_UUID_ASSIGNED_OFFSET 12
typedef uint64_t bt_gatt_id_t;
typedef struct bt_gatt_uuid {
uint8_t bytes[16];
} bt_gatt_uuid_t;
// ATT protocol error codes.
enum {
BT_GATT_ERR_NO_ERROR = 0x00,
BT_GATT_ERR_INVALID_HANDLE = 0x01,
BT_GATT_ERR_READ_NOT_PERMITTED = 0x02,
BT_GATT_ERR_WRITE_NOT_PERMITTED = 0x03,
BT_GATT_ERR_INVALID_PDU = 0x04,
BT_GATT_ERR_INSUFFICIENT_AUTHENTICATION = 0x05,
BT_GATT_ERR_REQUEST_NOT_SUPPORTED = 0x06,
BT_GATT_ERR_INVALID_OFFSET = 0x07,
BT_GATT_ERR_INSUFFICIENT_AUTHORIZATION = 0x08,
BT_GATT_ERR_PREPARE_QUEUE_FULL = 0x09,
BT_GATT_ERR_ATTRIBUTE_NOT_FOUND = 0x0A,
BT_GATT_ERR_ATTRIBUTENOTLONG = 0x0B,
BT_GATT_ERR_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0C,
BT_GATT_ERR_INVALID_ATTRIBUTE_VALUE_LENGTH = 0x0D,
BT_GATT_ERR_UNLIKELY_ERROR = 0x0E,
BT_GATT_ERR_INSUFFICIENT_ENCRYPTION = 0x0F,
BT_GATT_ERR_UNSUPPORTED_GROUP_TYPE = 0x10,
BT_GATT_ERR_INSUFFICIENT_RESOURCES = 0x11,
};
typedef uint8_t bt_gatt_err_t;
// Represents the status of a GATT operation.
typedef struct bt_gatt_status {
// Represents errors reported by the host (i.e. not over ATT).
zx_status_t status;
// ATT protocol error.
bt_gatt_err_t att_ecode;
} bt_gatt_status_t;
inline bool bt_gatt_status_is_success(bt_gatt_status_t* status) {
return (status->status == ZX_OK) &&
(status->att_ecode == BT_GATT_ERR_NO_ERROR);
}
// Possible values for the characteristic properties bitfield.
enum bt_gatt_chr_prop {
BT_GATT_CHR_PROP_BROADCAST = 0x01,
BT_GATT_CHR_PROP_READ = 0x02,
BT_GATT_CHR_PROP_WRITE_WITHOUT_RESPONSE = 0x04,
BT_GATT_CHR_PROP_WRITE = 0x08,
BT_GATT_CHR_PROP_NOTIFY = 0x10,
BT_GATT_CHR_PROP_INDICATE = 0x20,
BT_GATT_CHR_PROP_AUTHENTICATED_SIGNED_WRITES = 0x40,
BT_GATT_CHR_PROP_EXTENDED_PROPERTIES = 0x80,
};
typedef uint8_t bt_gatt_chr_prop_t;
enum bt_gatt_chr_ext_prop {
BT_GATT_CHR_EXT_PROP_RELIABLE_WRITE = 0x0100,
BT_GATT_CHR_EXT_PROP_WRITABLE_AUXILIARIES = 0x0200,
};
typedef uint16_t bt_gatt_chr_ext_prop_t;
// Represents a GATT characteristic descriptor.
typedef struct bt_gatt_descriptor {
bt_gatt_id_t id;
bt_gatt_uuid_t type;
} bt_gatt_descriptor_t;
// Represents a GATT characteristic.
typedef struct bt_gatt_chr {
bt_gatt_id_t id;
bt_gatt_uuid_t type;
// The bitmask of characteristic properties. The |extended_properties| field
// is populated if the "Characteristic Extended Properties" descriptor is
// present.
//
// See enums bt_gatt_chr_prop_t and bt_gatt_chr_ext_prop_t for possible
// bit values.
uint8_t properties;
uint16_t extended_properties;
size_t num_descriptors;
bt_gatt_descriptor_t* descriptors;
} bt_gatt_chr_t;
// Generic status result callback for all functions return just a status.
typedef void (*bt_gatt_status_cb)(void* cookie, bt_gatt_status_t status,
bt_gatt_id_t id);
// Result callback of the |connect| function. |status| will contain
// the result of the characteristic discovery procedure if it was initiated by
// |connect|. The service will be ready to receive further requests once this
// has been called successfully and the |status| callback has been called with success.
typedef void (*bt_gatt_connect_cb)(void* cookie, bt_gatt_status_t status,
const bt_gatt_chr_t* characteristics,
size_t characteristic_count);
// Result callback of the read related functions.
typedef void (*bt_gatt_read_characteristic_cb)(void* cookie,
bt_gatt_status_t status,
bt_gatt_id_t id,
const uint8_t* value,
size_t len);
// Value change notification callback of the |enable_notifications| function.
typedef void (*bt_gatt_notification_value_cb)(void* cookie, bt_gatt_id_t id,
const uint8_t* value, size_t len);
typedef struct bt_gatt_svc_ops {
// Connects to and starts characteristic discovery on the remote service.
zx_status_t (*connect)(void* ctx, void* cookie,
bt_gatt_connect_cb connect_cb);
// Stops this service and unregisters previously registered callbacks.
void (*stop)(void* ctx);
// Reads the value of the characteristic with the given ID.
//
// The |read_cb| callback will be called to asynchronously report the result
// of this operation.
zx_status_t (*read_characteristic)(void* ctx, bt_gatt_id_t id, void* cookie,
bt_gatt_read_characteristic_cb read_cb);
// Reads the long value of the characteristic with the given ID.
//
// The |read_cb| callback will be called to asynchronously report the result
// of this operation.
zx_status_t (*read_long_characteristic)(
void* ctx, bt_gatt_id_t id, void* cookie, uint16_t offset,
size_t max_bytes, bt_gatt_read_characteristic_cb read_cb);
zx_status_t (*write_characteristic)(void* ctx, bt_gatt_id_t id, void* cookie,
const uint8_t* buff, size_t len,
bt_gatt_status_cb read_cb);
// Enables notifications from the characteristic with the given ID. Returns
// ZX_ERR_BAD_STATE if the service has not been started yet.
//
// Returns ZX_ERR_SHOULD_WAIT if this request is already in progress.
//
// The |status_cb| callback will be called to asynchronously report the result
// of this operation.
zx_status_t (*enable_notifications)(void* ctx, bt_gatt_id_t id, void* cookie,
bt_gatt_status_cb status_cb,
bt_gatt_notification_value_cb value_cb);
} bt_gatt_svc_ops_t;
typedef struct bt_gatt_svc_proto {
bt_gatt_svc_ops_t* ops;
void* ctx;
} bt_gatt_svc_proto_t;
static inline zx_status_t bt_gatt_svc_connect(bt_gatt_svc_proto_t* svc,
void* cookie,
bt_gatt_connect_cb connect_cb) {
return svc->ops->connect(svc->ctx, cookie, connect_cb);
}
static inline void bt_gatt_svc_stop(bt_gatt_svc_proto_t* svc) {
svc->ops->stop(svc->ctx);
}
static inline zx_status_t bt_gatt_svc_read_characteristic(
bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie,
bt_gatt_read_characteristic_cb read_cb) {
return svc->ops->read_characteristic(svc->ctx, id, cookie, read_cb);
}
static inline zx_status_t bt_gatt_svc_read_long_characteristic(
bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie, uint16_t offset,
size_t max_bytes, bt_gatt_read_characteristic_cb read_cb) {
return svc->ops->read_long_characteristic(svc->ctx, id, cookie, offset,
max_bytes, read_cb);
}
static inline zx_status_t bt_gatt_svc_write_characteristic(
bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie,
const uint8_t* buff, size_t len, bt_gatt_status_cb status_cb) {
return svc->ops->write_characteristic(svc->ctx, id, cookie, buff, len,
status_cb);
}
static inline zx_status_t bt_gatt_svc_enable_notifications(
bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie,
bt_gatt_status_cb status_cb, bt_gatt_notification_value_cb value_cb) {
return svc->ops->enable_notifications(svc->ctx, id, cookie, status_cb,
value_cb);
}
// Convenience function to make a UUID from a 32-bit assigned value.
static inline bt_gatt_uuid_t bt_gatt_make_uuid32(uint32_t value) {
bt_gatt_uuid_t retval = {.bytes = BT_GATT_BASE_UUID};
retval.bytes[__BT_UUID_ASSIGNED_OFFSET] = (uint8_t)(value);
retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 1] = (uint8_t)(value >> 8);
retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 2] = (uint8_t)(value >> 16);
retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 3] = (uint8_t)(value >> 24);
return retval;
}
// Convenience function to make a UUID from a 16-bit assigned value.
static inline bt_gatt_uuid_t bt_gatt_make_uuid16(uint16_t value) {
return bt_gatt_make_uuid32((uint32_t)value);
}
// UUID comparsion.
// Note: this method only does a binary comparsion and doesn't break out low,
// mid, high, version, sequence, or node parts for indiviual comparison so
// doesn't conform to standard UUID sort.
static inline int bt_gatt_compare_uuid(const bt_gatt_uuid_t* u1,
const bt_gatt_uuid_t* u2) {
return memcmp(u1->bytes, u2->bytes, 16);
}
__END_CDECLS;