1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <string.h> 8 9#include <zircon/compiler.h> 10#include <zircon/types.h> 11 12__BEGIN_CDECLS; 13 14// BT SIG Base UUID for all 16/32 assigned UUID values. 15// 16// "00000000-0000-1000-8000-00805F9B34FB" 17// 18// (see Core Spec v5.0, Vol 3, Part B, Section 2.5.1) 19#define BT_GATT_BASE_UUID \ 20 { \ 21 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, \ 22 0x00, 0x00, 0x00, 0x00 \ 23 } 24 25#define __BT_UUID_ASSIGNED_OFFSET 12 26 27typedef uint64_t bt_gatt_id_t; 28 29typedef struct bt_gatt_uuid { 30 uint8_t bytes[16]; 31} bt_gatt_uuid_t; 32 33// ATT protocol error codes. 34enum { 35 BT_GATT_ERR_NO_ERROR = 0x00, 36 BT_GATT_ERR_INVALID_HANDLE = 0x01, 37 BT_GATT_ERR_READ_NOT_PERMITTED = 0x02, 38 BT_GATT_ERR_WRITE_NOT_PERMITTED = 0x03, 39 BT_GATT_ERR_INVALID_PDU = 0x04, 40 BT_GATT_ERR_INSUFFICIENT_AUTHENTICATION = 0x05, 41 BT_GATT_ERR_REQUEST_NOT_SUPPORTED = 0x06, 42 BT_GATT_ERR_INVALID_OFFSET = 0x07, 43 BT_GATT_ERR_INSUFFICIENT_AUTHORIZATION = 0x08, 44 BT_GATT_ERR_PREPARE_QUEUE_FULL = 0x09, 45 BT_GATT_ERR_ATTRIBUTE_NOT_FOUND = 0x0A, 46 BT_GATT_ERR_ATTRIBUTENOTLONG = 0x0B, 47 BT_GATT_ERR_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0C, 48 BT_GATT_ERR_INVALID_ATTRIBUTE_VALUE_LENGTH = 0x0D, 49 BT_GATT_ERR_UNLIKELY_ERROR = 0x0E, 50 BT_GATT_ERR_INSUFFICIENT_ENCRYPTION = 0x0F, 51 BT_GATT_ERR_UNSUPPORTED_GROUP_TYPE = 0x10, 52 BT_GATT_ERR_INSUFFICIENT_RESOURCES = 0x11, 53}; 54 55typedef uint8_t bt_gatt_err_t; 56 57// Represents the status of a GATT operation. 58typedef struct bt_gatt_status { 59 // Represents errors reported by the host (i.e. not over ATT). 60 zx_status_t status; 61 62 // ATT protocol error. 63 bt_gatt_err_t att_ecode; 64} bt_gatt_status_t; 65 66inline bool bt_gatt_status_is_success(bt_gatt_status_t* status) { 67 return (status->status == ZX_OK) && 68 (status->att_ecode == BT_GATT_ERR_NO_ERROR); 69} 70 71// Possible values for the characteristic properties bitfield. 72enum bt_gatt_chr_prop { 73 BT_GATT_CHR_PROP_BROADCAST = 0x01, 74 BT_GATT_CHR_PROP_READ = 0x02, 75 BT_GATT_CHR_PROP_WRITE_WITHOUT_RESPONSE = 0x04, 76 BT_GATT_CHR_PROP_WRITE = 0x08, 77 BT_GATT_CHR_PROP_NOTIFY = 0x10, 78 BT_GATT_CHR_PROP_INDICATE = 0x20, 79 BT_GATT_CHR_PROP_AUTHENTICATED_SIGNED_WRITES = 0x40, 80 BT_GATT_CHR_PROP_EXTENDED_PROPERTIES = 0x80, 81}; 82 83typedef uint8_t bt_gatt_chr_prop_t; 84 85enum bt_gatt_chr_ext_prop { 86 BT_GATT_CHR_EXT_PROP_RELIABLE_WRITE = 0x0100, 87 BT_GATT_CHR_EXT_PROP_WRITABLE_AUXILIARIES = 0x0200, 88}; 89 90typedef uint16_t bt_gatt_chr_ext_prop_t; 91 92// Represents a GATT characteristic descriptor. 93typedef struct bt_gatt_descriptor { 94 bt_gatt_id_t id; 95 bt_gatt_uuid_t type; 96} bt_gatt_descriptor_t; 97 98// Represents a GATT characteristic. 99typedef struct bt_gatt_chr { 100 bt_gatt_id_t id; 101 bt_gatt_uuid_t type; 102 103 // The bitmask of characteristic properties. The |extended_properties| field 104 // is populated if the "Characteristic Extended Properties" descriptor is 105 // present. 106 // 107 // See enums bt_gatt_chr_prop_t and bt_gatt_chr_ext_prop_t for possible 108 // bit values. 109 uint8_t properties; 110 uint16_t extended_properties; 111 112 size_t num_descriptors; 113 bt_gatt_descriptor_t* descriptors; 114} bt_gatt_chr_t; 115 116// Generic status result callback for all functions return just a status. 117typedef void (*bt_gatt_status_cb)(void* cookie, bt_gatt_status_t status, 118 bt_gatt_id_t id); 119 120// Result callback of the |connect| function. |status| will contain 121// the result of the characteristic discovery procedure if it was initiated by 122// |connect|. The service will be ready to receive further requests once this 123// has been called successfully and the |status| callback has been called with success. 124typedef void (*bt_gatt_connect_cb)(void* cookie, bt_gatt_status_t status, 125 const bt_gatt_chr_t* characteristics, 126 size_t characteristic_count); 127 128// Result callback of the read related functions. 129typedef void (*bt_gatt_read_characteristic_cb)(void* cookie, 130 bt_gatt_status_t status, 131 bt_gatt_id_t id, 132 const uint8_t* value, 133 size_t len); 134 135// Value change notification callback of the |enable_notifications| function. 136typedef void (*bt_gatt_notification_value_cb)(void* cookie, bt_gatt_id_t id, 137 const uint8_t* value, size_t len); 138 139typedef struct bt_gatt_svc_ops { 140 // Connects to and starts characteristic discovery on the remote service. 141 zx_status_t (*connect)(void* ctx, void* cookie, 142 bt_gatt_connect_cb connect_cb); 143 144 // Stops this service and unregisters previously registered callbacks. 145 void (*stop)(void* ctx); 146 147 // Reads the value of the characteristic with the given ID. 148 // 149 // The |read_cb| callback will be called to asynchronously report the result 150 // of this operation. 151 zx_status_t (*read_characteristic)(void* ctx, bt_gatt_id_t id, void* cookie, 152 bt_gatt_read_characteristic_cb read_cb); 153 154 // Reads the long value of the characteristic with the given ID. 155 // 156 // The |read_cb| callback will be called to asynchronously report the result 157 // of this operation. 158 zx_status_t (*read_long_characteristic)( 159 void* ctx, bt_gatt_id_t id, void* cookie, uint16_t offset, 160 size_t max_bytes, bt_gatt_read_characteristic_cb read_cb); 161 162 zx_status_t (*write_characteristic)(void* ctx, bt_gatt_id_t id, void* cookie, 163 const uint8_t* buff, size_t len, 164 bt_gatt_status_cb read_cb); 165 166 // Enables notifications from the characteristic with the given ID. Returns 167 // ZX_ERR_BAD_STATE if the service has not been started yet. 168 // 169 // Returns ZX_ERR_SHOULD_WAIT if this request is already in progress. 170 // 171 // The |status_cb| callback will be called to asynchronously report the result 172 // of this operation. 173 zx_status_t (*enable_notifications)(void* ctx, bt_gatt_id_t id, void* cookie, 174 bt_gatt_status_cb status_cb, 175 bt_gatt_notification_value_cb value_cb); 176} bt_gatt_svc_ops_t; 177 178typedef struct bt_gatt_svc_proto { 179 bt_gatt_svc_ops_t* ops; 180 void* ctx; 181} bt_gatt_svc_proto_t; 182 183static inline zx_status_t bt_gatt_svc_connect(bt_gatt_svc_proto_t* svc, 184 void* cookie, 185 bt_gatt_connect_cb connect_cb) { 186 return svc->ops->connect(svc->ctx, cookie, connect_cb); 187} 188 189static inline void bt_gatt_svc_stop(bt_gatt_svc_proto_t* svc) { 190 svc->ops->stop(svc->ctx); 191} 192 193static inline zx_status_t bt_gatt_svc_read_characteristic( 194 bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie, 195 bt_gatt_read_characteristic_cb read_cb) { 196 return svc->ops->read_characteristic(svc->ctx, id, cookie, read_cb); 197} 198 199static inline zx_status_t bt_gatt_svc_read_long_characteristic( 200 bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie, uint16_t offset, 201 size_t max_bytes, bt_gatt_read_characteristic_cb read_cb) { 202 return svc->ops->read_long_characteristic(svc->ctx, id, cookie, offset, 203 max_bytes, read_cb); 204} 205 206static inline zx_status_t bt_gatt_svc_write_characteristic( 207 bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie, 208 const uint8_t* buff, size_t len, bt_gatt_status_cb status_cb) { 209 return svc->ops->write_characteristic(svc->ctx, id, cookie, buff, len, 210 status_cb); 211} 212 213static inline zx_status_t bt_gatt_svc_enable_notifications( 214 bt_gatt_svc_proto_t* svc, bt_gatt_id_t id, void* cookie, 215 bt_gatt_status_cb status_cb, bt_gatt_notification_value_cb value_cb) { 216 return svc->ops->enable_notifications(svc->ctx, id, cookie, status_cb, 217 value_cb); 218} 219 220// Convenience function to make a UUID from a 32-bit assigned value. 221static inline bt_gatt_uuid_t bt_gatt_make_uuid32(uint32_t value) { 222 bt_gatt_uuid_t retval = {.bytes = BT_GATT_BASE_UUID}; 223 224 retval.bytes[__BT_UUID_ASSIGNED_OFFSET] = (uint8_t)(value); 225 retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 1] = (uint8_t)(value >> 8); 226 retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 2] = (uint8_t)(value >> 16); 227 retval.bytes[__BT_UUID_ASSIGNED_OFFSET + 3] = (uint8_t)(value >> 24); 228 229 return retval; 230} 231 232// Convenience function to make a UUID from a 16-bit assigned value. 233static inline bt_gatt_uuid_t bt_gatt_make_uuid16(uint16_t value) { 234 return bt_gatt_make_uuid32((uint32_t)value); 235} 236 237// UUID comparsion. 238// Note: this method only does a binary comparsion and doesn't break out low, 239// mid, high, version, sequence, or node parts for indiviual comparison so 240// doesn't conform to standard UUID sort. 241static inline int bt_gatt_compare_uuid(const bt_gatt_uuid_t* u1, 242 const bt_gatt_uuid_t* u2) { 243 return memcmp(u1->bytes, u2->bytes, 16); 244} 245 246__END_CDECLS; 247