BLE demo for mbed Ported RunningElectronics's SBDBT firmware for BLE. It can communicate with iOS

Dependencies:   FatFileSystem mbed

Fork of BTstack by Norimasa Okamoto

Committer:
todotani
Date:
Wed Feb 20 14:18:38 2013 +0000
Revision:
6:cf06ba884429
Parent:
1:6078e430af82
Change tick timer to 1ms. Change attribute 0xFFF1 as read of DigitalIn p5

Who changed what in which revision?

UserRevisionLine numberNew contents of line
todotani 1:6078e430af82 1 /*
todotani 1:6078e430af82 2 * Copyright (C) 2011-2012 by Matthias Ringwald
todotani 1:6078e430af82 3 *
todotani 1:6078e430af82 4 * Redistribution and use in source and binary forms, with or without
todotani 1:6078e430af82 5 * modification, are permitted provided that the following conditions
todotani 1:6078e430af82 6 * are met:
todotani 1:6078e430af82 7 *
todotani 1:6078e430af82 8 * 1. Redistributions of source code must retain the above copyright
todotani 1:6078e430af82 9 * notice, this list of conditions and the following disclaimer.
todotani 1:6078e430af82 10 * 2. Redistributions in binary form must reproduce the above copyright
todotani 1:6078e430af82 11 * notice, this list of conditions and the following disclaimer in the
todotani 1:6078e430af82 12 * documentation and/or other materials provided with the distribution.
todotani 1:6078e430af82 13 * 3. Neither the name of the copyright holders nor the names of
todotani 1:6078e430af82 14 * contributors may be used to endorse or promote products derived
todotani 1:6078e430af82 15 * from this software without specific prior written permission.
todotani 1:6078e430af82 16 * 4. Any redistribution, use, or modification is done solely for
todotani 1:6078e430af82 17 * personal benefit and not for any commercial purpose or for
todotani 1:6078e430af82 18 * monetary gain.
todotani 1:6078e430af82 19 *
todotani 1:6078e430af82 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
todotani 1:6078e430af82 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
todotani 1:6078e430af82 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
todotani 1:6078e430af82 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
todotani 1:6078e430af82 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
todotani 1:6078e430af82 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
todotani 1:6078e430af82 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
todotani 1:6078e430af82 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
todotani 1:6078e430af82 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
todotani 1:6078e430af82 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
todotani 1:6078e430af82 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
todotani 1:6078e430af82 31 * SUCH DAMAGE.
todotani 1:6078e430af82 32 *
todotani 1:6078e430af82 33 * Please inquire about commercial licensing options at btstack@ringwald.ch
todotani 1:6078e430af82 34 *
todotani 1:6078e430af82 35 */
todotani 1:6078e430af82 36
todotani 1:6078e430af82 37 #include <stdio.h>
todotani 1:6078e430af82 38 #include <string.h>
todotani 1:6078e430af82 39
todotani 1:6078e430af82 40 #include "att.h"
todotani 6:cf06ba884429 41 #include "debug.h"
todotani 1:6078e430af82 42
todotani 1:6078e430af82 43 // from src/utils.
todotani 1:6078e430af82 44 #define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
todotani 1:6078e430af82 45
todotani 1:6078e430af82 46 // Buetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian
todotani 1:6078e430af82 47 static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
todotani 1:6078e430af82 48
todotani 1:6078e430af82 49 static void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
todotani 1:6078e430af82 50 buffer[pos++] = value;
todotani 1:6078e430af82 51 buffer[pos++] = value >> 8;
todotani 1:6078e430af82 52 }
todotani 1:6078e430af82 53
todotani 1:6078e430af82 54 static void hexdump2(void const *data, int size){
todotani 1:6078e430af82 55 int i;
todotani 1:6078e430af82 56 for (i=0; i<size;i++){
todotani 6:cf06ba884429 57 log_info("%02X ", ((uint8_t *)data)[i]);
todotani 1:6078e430af82 58 }
todotani 6:cf06ba884429 59 log_info("\n");
todotani 1:6078e430af82 60 }
todotani 1:6078e430af82 61
todotani 1:6078e430af82 62 static void printUUID128(const uint8_t * uuid){
todotani 1:6078e430af82 63 int i;
todotani 1:6078e430af82 64 for (i=15; i >= 0 ; i--){
todotani 6:cf06ba884429 65 log_info("%02X", uuid[i]);
todotani 1:6078e430af82 66 switch (i){
todotani 1:6078e430af82 67 case 4:
todotani 1:6078e430af82 68 case 6:
todotani 1:6078e430af82 69 case 8:
todotani 1:6078e430af82 70 case 10:
todotani 6:cf06ba884429 71 log_info("-");
todotani 1:6078e430af82 72 break;
todotani 1:6078e430af82 73 default:
todotani 1:6078e430af82 74 break;
todotani 1:6078e430af82 75 }
todotani 1:6078e430af82 76 }
todotani 1:6078e430af82 77 }
todotani 1:6078e430af82 78
todotani 1:6078e430af82 79 static int is_Bluetooth_Base_UUID(uint8_t const *uuid){
todotani 1:6078e430af82 80 if (memcmp(&uuid[0], &bluetooth_base_uuid[0], 12)) return 0;
todotani 1:6078e430af82 81 if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0;
todotani 1:6078e430af82 82 return 1;
todotani 1:6078e430af82 83
todotani 1:6078e430af82 84 }
todotani 1:6078e430af82 85
todotani 1:6078e430af82 86 // ATT Database
todotani 1:6078e430af82 87 static uint8_t const * att_db = NULL;
todotani 1:6078e430af82 88 static att_read_callback_t att_read_callback = NULL;
todotani 1:6078e430af82 89 static att_write_callback_t att_write_callback = NULL;
todotani 1:6078e430af82 90
todotani 1:6078e430af82 91 // new java-style iterator
todotani 1:6078e430af82 92 typedef struct att_iterator {
todotani 1:6078e430af82 93 // private
todotani 1:6078e430af82 94 uint8_t const * att_ptr;
todotani 1:6078e430af82 95 // public
todotani 1:6078e430af82 96 uint16_t size;
todotani 1:6078e430af82 97 uint16_t flags;
todotani 1:6078e430af82 98 uint16_t handle;
todotani 1:6078e430af82 99 uint8_t const * uuid;
todotani 1:6078e430af82 100 uint16_t value_len;
todotani 1:6078e430af82 101 uint8_t const * value;
todotani 1:6078e430af82 102 } att_iterator_t;
todotani 1:6078e430af82 103
todotani 1:6078e430af82 104 void att_iterator_init(att_iterator_t *it){
todotani 1:6078e430af82 105 it->att_ptr = att_db;
todotani 1:6078e430af82 106 }
todotani 1:6078e430af82 107
todotani 1:6078e430af82 108 int att_iterator_has_next(att_iterator_t *it){
todotani 1:6078e430af82 109 return it->att_ptr != NULL;
todotani 1:6078e430af82 110 }
todotani 1:6078e430af82 111
todotani 1:6078e430af82 112 void att_iterator_fetch_next(att_iterator_t *it){
todotani 1:6078e430af82 113 it->size = READ_BT_16(it->att_ptr, 0);
todotani 1:6078e430af82 114 if (it->size == 0){
todotani 1:6078e430af82 115 it->flags = 0;
todotani 1:6078e430af82 116 it->handle = 0;
todotani 1:6078e430af82 117 it->uuid = NULL;
todotani 1:6078e430af82 118 it->value_len = 0;
todotani 1:6078e430af82 119 it->value = NULL;
todotani 1:6078e430af82 120 it->att_ptr = NULL;
todotani 1:6078e430af82 121 return;
todotani 1:6078e430af82 122 }
todotani 1:6078e430af82 123 it->flags = READ_BT_16(it->att_ptr, 2);
todotani 1:6078e430af82 124 it->handle = READ_BT_16(it->att_ptr, 4);
todotani 1:6078e430af82 125 it->uuid = &it->att_ptr[6];
todotani 1:6078e430af82 126 // handle 128 bit UUIDs
todotani 1:6078e430af82 127 if (it->flags & ATT_PROPERTY_UUID128){
todotani 1:6078e430af82 128 it->value_len = it->size - 22;
todotani 1:6078e430af82 129 it->value = &it->att_ptr[22];
todotani 1:6078e430af82 130 } else {
todotani 1:6078e430af82 131 it->value_len = it->size - 8;
todotani 1:6078e430af82 132 it->value = &it->att_ptr[8];
todotani 1:6078e430af82 133 }
todotani 1:6078e430af82 134 // advance AFTER setting values
todotani 1:6078e430af82 135 it->att_ptr += it->size;
todotani 1:6078e430af82 136 }
todotani 1:6078e430af82 137
todotani 1:6078e430af82 138 int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){
todotani 1:6078e430af82 139 if (it->handle == 0) return 0;
todotani 1:6078e430af82 140 if (it->flags & ATT_PROPERTY_UUID128){
todotani 1:6078e430af82 141 if (!is_Bluetooth_Base_UUID(it->uuid)) return 0;
todotani 1:6078e430af82 142 return READ_BT_16(it->uuid, 12) == uuid;
todotani 1:6078e430af82 143 }
todotani 1:6078e430af82 144 return READ_BT_16(it->uuid, 0) == uuid;
todotani 1:6078e430af82 145 }
todotani 1:6078e430af82 146
todotani 1:6078e430af82 147 int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){
todotani 1:6078e430af82 148 if (it->handle == 0) return 0;
todotani 1:6078e430af82 149 // input: UUID16
todotani 1:6078e430af82 150 if (uuid_len == 2) {
todotani 1:6078e430af82 151 return att_iterator_match_uuid16(it, READ_BT_16(uuid, 0));
todotani 1:6078e430af82 152 }
todotani 1:6078e430af82 153 // input and db: UUID128
todotani 1:6078e430af82 154 if (it->flags & ATT_PROPERTY_UUID128){
todotani 1:6078e430af82 155 return memcmp(it->uuid, uuid, 16) == 0;
todotani 1:6078e430af82 156 }
todotani 1:6078e430af82 157 // input: UUID128, db: UUID16
todotani 1:6078e430af82 158 if (!is_Bluetooth_Base_UUID(uuid)) return 0;
todotani 1:6078e430af82 159 return READ_BT_16(uuid, 12) == READ_BT_16(it->uuid, 0);
todotani 1:6078e430af82 160 }
todotani 1:6078e430af82 161
todotani 1:6078e430af82 162
todotani 1:6078e430af82 163 int att_find_handle(att_iterator_t *it, uint16_t handle){
todotani 1:6078e430af82 164 att_iterator_init(it);
todotani 1:6078e430af82 165 while (att_iterator_has_next(it)){
todotani 1:6078e430af82 166 att_iterator_fetch_next(it);
todotani 1:6078e430af82 167 if (it->handle != handle) continue;
todotani 1:6078e430af82 168 return 1;
todotani 1:6078e430af82 169 }
todotani 1:6078e430af82 170 return 0;
todotani 1:6078e430af82 171 }
todotani 1:6078e430af82 172
todotani 1:6078e430af82 173 static void att_update_value_len(att_iterator_t *it){
todotani 1:6078e430af82 174 if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0 || !att_read_callback) return;
todotani 1:6078e430af82 175 it->value_len = (*att_read_callback)(it->handle, 0, NULL, 0);
todotani 1:6078e430af82 176 return;
todotani 1:6078e430af82 177 }
todotani 1:6078e430af82 178
todotani 1:6078e430af82 179 static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
todotani 1:6078e430af82 180
todotani 1:6078e430af82 181 // DYNAMIC
todotani 1:6078e430af82 182 if ((it->flags & ATT_PROPERTY_DYNAMIC) && att_read_callback) {
todotani 1:6078e430af82 183 return (*att_read_callback)(it->handle, offset, buffer, buffer_size);
todotani 1:6078e430af82 184 }
todotani 1:6078e430af82 185
todotani 1:6078e430af82 186 // STATIC
todotani 1:6078e430af82 187 uint16_t bytes_to_copy = it->value_len;
todotani 1:6078e430af82 188 if (bytes_to_copy > buffer_size){
todotani 1:6078e430af82 189 bytes_to_copy = buffer_size;
todotani 1:6078e430af82 190 }
todotani 1:6078e430af82 191 memcpy(buffer, it->value, bytes_to_copy);
todotani 1:6078e430af82 192 return bytes_to_copy;
todotani 1:6078e430af82 193 }
todotani 1:6078e430af82 194
todotani 1:6078e430af82 195 void att_set_db(uint8_t const * db){
todotani 1:6078e430af82 196 att_db = db;
todotani 1:6078e430af82 197 }
todotani 1:6078e430af82 198
todotani 1:6078e430af82 199 void att_set_read_callback(att_read_callback_t callback){
todotani 1:6078e430af82 200 att_read_callback = callback;
todotani 1:6078e430af82 201 }
todotani 1:6078e430af82 202
todotani 1:6078e430af82 203 void att_set_write_callback(att_write_callback_t callback){
todotani 1:6078e430af82 204 att_write_callback = callback;
todotani 1:6078e430af82 205 }
todotani 1:6078e430af82 206
todotani 1:6078e430af82 207 void att_dump_attributes(void){
todotani 1:6078e430af82 208 att_iterator_t it;
todotani 1:6078e430af82 209 att_iterator_init(&it);
todotani 1:6078e430af82 210 while (att_iterator_has_next(&it)){
todotani 1:6078e430af82 211 att_iterator_fetch_next(&it);
todotani 1:6078e430af82 212 if (it.handle == 0) {
todotani 6:cf06ba884429 213 log_info("Handle: END\n");
todotani 1:6078e430af82 214 return;
todotani 1:6078e430af82 215 }
todotani 6:cf06ba884429 216 log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags);
todotani 1:6078e430af82 217 if (it.flags & ATT_PROPERTY_UUID128){
todotani 1:6078e430af82 218 printUUID128(it.uuid);
todotani 1:6078e430af82 219 } else {
todotani 6:cf06ba884429 220 log_info("%04x", READ_BT_16(it.uuid, 0));
todotani 1:6078e430af82 221 }
todotani 6:cf06ba884429 222 log_info(", value_len: %u, value: ", it.value_len);
todotani 1:6078e430af82 223 hexdump2(it.value, it.value_len);
todotani 1:6078e430af82 224 }
todotani 1:6078e430af82 225 }
todotani 1:6078e430af82 226
todotani 1:6078e430af82 227 static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){
todotani 1:6078e430af82 228 response_buffer[0] = ATT_ERROR_RESPONSE;
todotani 1:6078e430af82 229 response_buffer[1] = request;
todotani 1:6078e430af82 230 bt_store_16(response_buffer, 2, handle);
todotani 1:6078e430af82 231 response_buffer[4] = error_code;
todotani 1:6078e430af82 232 return 5;
todotani 1:6078e430af82 233 }
todotani 1:6078e430af82 234
todotani 1:6078e430af82 235 static uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){
todotani 1:6078e430af82 236 return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
todotani 1:6078e430af82 237 }
todotani 1:6078e430af82 238
todotani 1:6078e430af82 239 static uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){
todotani 1:6078e430af82 240 return setup_error(response_buffer, request, handle, ATT_ERROR_ATTRIBUTE_INVALID);
todotani 1:6078e430af82 241 }
todotani 1:6078e430af82 242
todotani 1:6078e430af82 243 static uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){
todotani 1:6078e430af82 244 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET);
todotani 1:6078e430af82 245 }
todotani 1:6078e430af82 246
todotani 1:6078e430af82 247 //
todotani 1:6078e430af82 248 // MARK: ATT_EXCHANGE_MTU_REQUEST
todotani 1:6078e430af82 249 //
todotani 1:6078e430af82 250 static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 251 uint8_t * response_buffer){
todotani 1:6078e430af82 252
todotani 1:6078e430af82 253 uint16_t client_rx_mtu = READ_BT_16(request_buffer, 1);
todotani 1:6078e430af82 254 if (client_rx_mtu < att_connection->mtu){
todotani 1:6078e430af82 255 att_connection->mtu = client_rx_mtu;
todotani 1:6078e430af82 256 }
todotani 1:6078e430af82 257
todotani 1:6078e430af82 258 response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE;
todotani 1:6078e430af82 259 bt_store_16(response_buffer, 1, att_connection->mtu);
todotani 1:6078e430af82 260 return 3;
todotani 1:6078e430af82 261 }
todotani 1:6078e430af82 262
todotani 1:6078e430af82 263
todotani 1:6078e430af82 264 //
todotani 1:6078e430af82 265 // MARK: ATT_FIND_INFORMATION_REQUEST
todotani 1:6078e430af82 266 //
todotani 1:6078e430af82 267 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
todotani 1:6078e430af82 268 //
todotani 1:6078e430af82 269 static uint16_t handle_find_information_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
todotani 1:6078e430af82 270 uint16_t start_handle, uint16_t end_handle){
todotani 1:6078e430af82 271
todotani 6:cf06ba884429 272 log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X\n", start_handle, end_handle);
todotani 1:6078e430af82 273
todotani 1:6078e430af82 274 uint16_t offset = 1;
todotani 1:6078e430af82 275 uint16_t pair_len = 0;
todotani 1:6078e430af82 276
todotani 1:6078e430af82 277 att_iterator_t it;
todotani 1:6078e430af82 278 att_iterator_init(&it);
todotani 1:6078e430af82 279 while (att_iterator_has_next(&it)){
todotani 1:6078e430af82 280 att_iterator_fetch_next(&it);
todotani 1:6078e430af82 281 if (!it.handle) break;
todotani 1:6078e430af82 282 if (it.handle > end_handle) break;
todotani 1:6078e430af82 283 if (it.handle < start_handle) continue;
todotani 1:6078e430af82 284
todotani 1:6078e430af82 285 att_update_value_len(&it);
todotani 1:6078e430af82 286
todotani 6:cf06ba884429 287 // log_debug("Handle 0x%04x\n", it.handle);
todotani 1:6078e430af82 288
todotani 1:6078e430af82 289 // check if value has same len as last one
todotani 1:6078e430af82 290 uint16_t this_pair_len = 2 + it.value_len;
todotani 1:6078e430af82 291 if (offset > 1){
todotani 1:6078e430af82 292 if (pair_len != this_pair_len) {
todotani 1:6078e430af82 293 break;
todotani 1:6078e430af82 294 }
todotani 1:6078e430af82 295 }
todotani 1:6078e430af82 296
todotani 1:6078e430af82 297 // first
todotani 1:6078e430af82 298 if (offset == 1) {
todotani 1:6078e430af82 299 pair_len = this_pair_len;
todotani 1:6078e430af82 300 if (it.value_len == 2) {
todotani 1:6078e430af82 301 response_buffer[offset] = 0x01; // format
todotani 1:6078e430af82 302 } else {
todotani 1:6078e430af82 303 response_buffer[offset] = 0x02;
todotani 1:6078e430af82 304 }
todotani 1:6078e430af82 305 offset++;
todotani 1:6078e430af82 306 }
todotani 1:6078e430af82 307
todotani 1:6078e430af82 308 // space?
todotani 1:6078e430af82 309 if (offset + pair_len > response_buffer_size) {
todotani 1:6078e430af82 310 if (offset > 2) break;
todotani 1:6078e430af82 311 it.value_len = response_buffer_size - 4;
todotani 1:6078e430af82 312 }
todotani 1:6078e430af82 313
todotani 1:6078e430af82 314 // store
todotani 1:6078e430af82 315 bt_store_16(response_buffer, offset, it.handle);
todotani 1:6078e430af82 316 offset += 2;
todotani 1:6078e430af82 317 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
todotani 1:6078e430af82 318 offset += bytes_copied;
todotani 1:6078e430af82 319 }
todotani 1:6078e430af82 320
todotani 1:6078e430af82 321 if (offset == 1){
todotani 1:6078e430af82 322 return setup_error_atribute_not_found(response_buffer, ATT_FIND_INFORMATION_REQUEST, start_handle);
todotani 1:6078e430af82 323 }
todotani 1:6078e430af82 324
todotani 1:6078e430af82 325 response_buffer[0] = ATT_FIND_INFORMATION_REPLY;
todotani 1:6078e430af82 326 return offset;
todotani 1:6078e430af82 327 }
todotani 1:6078e430af82 328
todotani 1:6078e430af82 329 static uint16_t handle_find_information_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 330 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 331 return handle_find_information_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3));
todotani 1:6078e430af82 332 }
todotani 1:6078e430af82 333
todotani 1:6078e430af82 334 //
todotani 1:6078e430af82 335 // MARK: ATT_FIND_BY_TYPE_VALUE
todotani 1:6078e430af82 336 //
todotani 1:6078e430af82 337 // "Only attributes with attribute handles between and including the Starting Handle parameter
todotani 1:6078e430af82 338 // and the Ending Handle parameter that match the requested attri- bute type and the attribute
todotani 1:6078e430af82 339 // value that have sufficient permissions to allow reading will be returned" -> (1)
todotani 1:6078e430af82 340 //
todotani 1:6078e430af82 341 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
todotani 1:6078e430af82 342 //
todotani 1:6078e430af82 343 // NOTE: doesn't handle DYNAMIC values
todotani 1:6078e430af82 344 // NOTE: only supports 16 bit UUIDs
todotani 1:6078e430af82 345 //
todotani 1:6078e430af82 346 static uint16_t handle_find_by_type_value_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
todotani 1:6078e430af82 347 uint16_t start_handle, uint16_t end_handle,
todotani 1:6078e430af82 348 uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){
todotani 1:6078e430af82 349
todotani 6:cf06ba884429 350 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type);
todotani 1:6078e430af82 351 hexdump2(attribute_value, attribute_len);
todotani 1:6078e430af82 352
todotani 1:6078e430af82 353 uint16_t offset = 1;
todotani 1:6078e430af82 354 uint16_t in_group = 0;
todotani 1:6078e430af82 355 uint16_t prev_handle = 0;
todotani 1:6078e430af82 356
todotani 1:6078e430af82 357 att_iterator_t it;
todotani 1:6078e430af82 358 att_iterator_init(&it);
todotani 1:6078e430af82 359 while (att_iterator_has_next(&it)){
todotani 1:6078e430af82 360 att_iterator_fetch_next(&it);
todotani 1:6078e430af82 361
todotani 1:6078e430af82 362 if (it.handle && it.handle < start_handle) continue;
todotani 1:6078e430af82 363 if (it.handle > end_handle) break; // (1)
todotani 1:6078e430af82 364
todotani 1:6078e430af82 365 // close current tag, if within a group and a new service definition starts or we reach end of att db
todotani 1:6078e430af82 366 if (in_group &&
todotani 1:6078e430af82 367 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
todotani 1:6078e430af82 368
todotani 6:cf06ba884429 369 log_info("End of group, handle 0x%04x\n", prev_handle);
todotani 1:6078e430af82 370 bt_store_16(response_buffer, offset, prev_handle);
todotani 1:6078e430af82 371 offset += 2;
todotani 1:6078e430af82 372 in_group = 0;
todotani 1:6078e430af82 373
todotani 1:6078e430af82 374 // check if space for another handle pair available
todotani 1:6078e430af82 375 if (offset + 4 > response_buffer_size){
todotani 1:6078e430af82 376 break;
todotani 1:6078e430af82 377 }
todotani 1:6078e430af82 378 }
todotani 1:6078e430af82 379
todotani 1:6078e430af82 380 // keep track of previous handle
todotani 1:6078e430af82 381 prev_handle = it.handle;
todotani 1:6078e430af82 382
todotani 1:6078e430af82 383 // does current attribute match
todotani 1:6078e430af82 384 if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
todotani 6:cf06ba884429 385 log_info("Begin of group, handle 0x%04x\n", it.handle);
todotani 1:6078e430af82 386 bt_store_16(response_buffer, offset, it.handle);
todotani 1:6078e430af82 387 offset += 2;
todotani 1:6078e430af82 388 in_group = 1;
todotani 1:6078e430af82 389 }
todotani 1:6078e430af82 390 }
todotani 1:6078e430af82 391
todotani 1:6078e430af82 392 if (offset == 1){
todotani 1:6078e430af82 393 return setup_error_atribute_not_found(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST, start_handle);
todotani 1:6078e430af82 394 }
todotani 1:6078e430af82 395
todotani 1:6078e430af82 396 response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE;
todotani 1:6078e430af82 397 return offset;
todotani 1:6078e430af82 398 }
todotani 1:6078e430af82 399
todotani 1:6078e430af82 400 static uint16_t handle_find_by_type_value_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 401 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 402 int attribute_len = request_len - 7;
todotani 1:6078e430af82 403 return handle_find_by_type_value_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1),
todotani 1:6078e430af82 404 READ_BT_16(request_buffer, 3), READ_BT_16(request_buffer, 5), attribute_len, &request_buffer[7]);
todotani 1:6078e430af82 405 }
todotani 1:6078e430af82 406
todotani 1:6078e430af82 407 //
todotani 1:6078e430af82 408 // MARK: ATT_READ_BY_TYPE_REQUEST
todotani 1:6078e430af82 409 //
todotani 1:6078e430af82 410 static uint16_t handle_read_by_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
todotani 1:6078e430af82 411 uint16_t start_handle, uint16_t end_handle,
todotani 1:6078e430af82 412 uint16_t attribute_type_len, uint8_t * attribute_type){
todotani 1:6078e430af82 413
todotani 6:cf06ba884429 414 log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle);
todotani 1:6078e430af82 415 hexdump2(attribute_type, attribute_type_len);
todotani 1:6078e430af82 416
todotani 1:6078e430af82 417 uint16_t offset = 1;
todotani 1:6078e430af82 418 uint16_t pair_len = 0;
todotani 1:6078e430af82 419
todotani 1:6078e430af82 420 att_iterator_t it;
todotani 1:6078e430af82 421 att_iterator_init(&it);
todotani 1:6078e430af82 422 while (att_iterator_has_next(&it)){
todotani 1:6078e430af82 423 att_iterator_fetch_next(&it);
todotani 1:6078e430af82 424
todotani 1:6078e430af82 425 if (!it.handle) break;
todotani 1:6078e430af82 426 if (it.handle < start_handle) continue;
todotani 1:6078e430af82 427 if (it.handle > end_handle) break; // (1)
todotani 1:6078e430af82 428
todotani 1:6078e430af82 429 // does current attribute match
todotani 1:6078e430af82 430 if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue;
todotani 1:6078e430af82 431
todotani 1:6078e430af82 432 att_update_value_len(&it);
todotani 1:6078e430af82 433
todotani 1:6078e430af82 434 // check if value has same len as last one
todotani 1:6078e430af82 435 uint16_t this_pair_len = 2 + it.value_len;
todotani 1:6078e430af82 436 if (offset > 1){
todotani 1:6078e430af82 437 if (pair_len != this_pair_len) {
todotani 1:6078e430af82 438 break;
todotani 1:6078e430af82 439 }
todotani 1:6078e430af82 440 }
todotani 1:6078e430af82 441
todotani 1:6078e430af82 442 // first
todotani 1:6078e430af82 443 if (offset == 1) {
todotani 1:6078e430af82 444 pair_len = this_pair_len;
todotani 1:6078e430af82 445 response_buffer[offset] = pair_len;
todotani 1:6078e430af82 446 offset++;
todotani 1:6078e430af82 447 }
todotani 1:6078e430af82 448
todotani 1:6078e430af82 449 // space?
todotani 1:6078e430af82 450 if (offset + pair_len > response_buffer_size) {
todotani 1:6078e430af82 451 if (offset > 2) break;
todotani 1:6078e430af82 452 it.value_len = response_buffer_size - 4;
todotani 1:6078e430af82 453 }
todotani 1:6078e430af82 454
todotani 1:6078e430af82 455 // store
todotani 1:6078e430af82 456 bt_store_16(response_buffer, offset, it.handle);
todotani 1:6078e430af82 457 offset += 2;
todotani 1:6078e430af82 458 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
todotani 1:6078e430af82 459 offset += bytes_copied;
todotani 1:6078e430af82 460 }
todotani 1:6078e430af82 461
todotani 1:6078e430af82 462 if (offset == 1){
todotani 1:6078e430af82 463 return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_TYPE_REQUEST, start_handle);
todotani 1:6078e430af82 464 }
todotani 1:6078e430af82 465
todotani 1:6078e430af82 466 response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE;
todotani 1:6078e430af82 467 return offset;
todotani 1:6078e430af82 468 }
todotani 1:6078e430af82 469
todotani 1:6078e430af82 470 static uint16_t handle_read_by_type_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 471 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 472 int attribute_type_len;
todotani 1:6078e430af82 473 if (request_len <= 7){
todotani 1:6078e430af82 474 attribute_type_len = 2;
todotani 1:6078e430af82 475 } else {
todotani 1:6078e430af82 476 attribute_type_len = 16;
todotani 1:6078e430af82 477 }
todotani 1:6078e430af82 478 return handle_read_by_type_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
todotani 1:6078e430af82 479 }
todotani 1:6078e430af82 480
todotani 1:6078e430af82 481 //
todotani 1:6078e430af82 482 // MARK: ATT_READ_BY_TYPE_REQUEST
todotani 1:6078e430af82 483 //
todotani 1:6078e430af82 484 static uint16_t handle_read_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){
todotani 1:6078e430af82 485
todotani 6:cf06ba884429 486 log_info("ATT_READ_REQUEST: handle %04x\n", handle);
todotani 1:6078e430af82 487
todotani 1:6078e430af82 488 att_iterator_t it;
todotani 1:6078e430af82 489 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 490 if (!ok){
todotani 1:6078e430af82 491 return setup_error_atribute_not_found(response_buffer, ATT_READ_REQUEST, handle);
todotani 1:6078e430af82 492 }
todotani 6:cf06ba884429 493
todotani 1:6078e430af82 494 att_update_value_len(&it);
todotani 1:6078e430af82 495
todotani 1:6078e430af82 496 uint16_t offset = 1;
todotani 1:6078e430af82 497 // limit data
todotani 1:6078e430af82 498 if (offset + it.value_len > response_buffer_size) {
todotani 1:6078e430af82 499 it.value_len = response_buffer_size - 1;
todotani 1:6078e430af82 500 }
todotani 1:6078e430af82 501
todotani 1:6078e430af82 502 // store
todotani 1:6078e430af82 503 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
todotani 1:6078e430af82 504 offset += bytes_copied;
todotani 1:6078e430af82 505
todotani 1:6078e430af82 506 response_buffer[0] = ATT_READ_RESPONSE;
todotani 1:6078e430af82 507 return offset;
todotani 1:6078e430af82 508 }
todotani 1:6078e430af82 509
todotani 1:6078e430af82 510 static uint16_t handle_read_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 511 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 512 return handle_read_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1));
todotani 1:6078e430af82 513 }
todotani 1:6078e430af82 514
todotani 1:6078e430af82 515 //
todotani 1:6078e430af82 516 // MARK: ATT_READ_BLOB_REQUEST 0x0c
todotani 1:6078e430af82 517 //
todotani 1:6078e430af82 518 static uint16_t handle_read_blob_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){
todotani 6:cf06ba884429 519 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u\n", handle, value_offset);
todotani 1:6078e430af82 520
todotani 1:6078e430af82 521 att_iterator_t it;
todotani 1:6078e430af82 522 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 523 if (!ok){
todotani 1:6078e430af82 524 return setup_error_atribute_not_found(response_buffer, ATT_READ_BLOB_REQUEST, handle);
todotani 1:6078e430af82 525 }
todotani 1:6078e430af82 526
todotani 1:6078e430af82 527 att_update_value_len(&it);
todotani 1:6078e430af82 528
todotani 1:6078e430af82 529 if (value_offset >= it.value_len){
todotani 1:6078e430af82 530 return setup_error_invalid_offset(response_buffer, ATT_READ_BLOB_REQUEST, handle);
todotani 1:6078e430af82 531 }
todotani 1:6078e430af82 532
todotani 1:6078e430af82 533 // limit data
todotani 1:6078e430af82 534 uint16_t offset = 1;
todotani 1:6078e430af82 535 if (offset + it.value_len - value_offset > response_buffer_size) {
todotani 1:6078e430af82 536 it.value_len = response_buffer_size - 1 + value_offset;
todotani 1:6078e430af82 537 }
todotani 1:6078e430af82 538
todotani 1:6078e430af82 539 // store
todotani 1:6078e430af82 540 uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset);
todotani 1:6078e430af82 541 offset += bytes_copied;
todotani 1:6078e430af82 542
todotani 1:6078e430af82 543 response_buffer[0] = ATT_READ_BLOB_RESPONSE;
todotani 1:6078e430af82 544 return offset;
todotani 1:6078e430af82 545 }
todotani 1:6078e430af82 546
todotani 1:6078e430af82 547 uint16_t handle_read_blob_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 548 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 549 return handle_read_blob_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3));
todotani 1:6078e430af82 550 }
todotani 1:6078e430af82 551
todotani 1:6078e430af82 552 //
todotani 1:6078e430af82 553 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e
todotani 1:6078e430af82 554 //
todotani 1:6078e430af82 555 static uint16_t handle_read_multiple_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint16_t * handles){
todotani 6:cf06ba884429 556 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u\n", num_handles);
todotani 1:6078e430af82 557
todotani 1:6078e430af82 558 uint16_t offset = 1;
todotani 1:6078e430af82 559
todotani 1:6078e430af82 560 int i;
todotani 1:6078e430af82 561 for (i=0;i<num_handles;i++){
todotani 1:6078e430af82 562 uint16_t handle = handles[i];
todotani 1:6078e430af82 563
todotani 1:6078e430af82 564 if (handle == 0){
todotani 1:6078e430af82 565 return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle);
todotani 1:6078e430af82 566 }
todotani 1:6078e430af82 567
todotani 1:6078e430af82 568 att_iterator_t it;
todotani 1:6078e430af82 569
todotani 1:6078e430af82 570 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 571 if (!ok){
todotani 1:6078e430af82 572 return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle);
todotani 1:6078e430af82 573 }
todotani 1:6078e430af82 574
todotani 1:6078e430af82 575 att_update_value_len(&it);
todotani 1:6078e430af82 576
todotani 1:6078e430af82 577 // limit data
todotani 1:6078e430af82 578 if (offset + it.value_len > response_buffer_size) {
todotani 1:6078e430af82 579 it.value_len = response_buffer_size - 1;
todotani 1:6078e430af82 580 }
todotani 1:6078e430af82 581
todotani 1:6078e430af82 582 // store
todotani 1:6078e430af82 583 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
todotani 1:6078e430af82 584 offset += bytes_copied;
todotani 1:6078e430af82 585 }
todotani 1:6078e430af82 586
todotani 1:6078e430af82 587 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE;
todotani 1:6078e430af82 588 return offset;
todotani 1:6078e430af82 589 }
todotani 1:6078e430af82 590 uint16_t handle_read_multiple_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 591 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 592 int num_handles = (request_len - 1) >> 1;
todotani 1:6078e430af82 593 return handle_read_multiple_request2(response_buffer, response_buffer_size, num_handles, (uint16_t*) &request_buffer[1]);
todotani 1:6078e430af82 594 }
todotani 1:6078e430af82 595
todotani 1:6078e430af82 596 //
todotani 1:6078e430af82 597 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
todotani 1:6078e430af82 598 //
todotani 1:6078e430af82 599 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
todotani 1:6078e430af82 600 //
todotani 1:6078e430af82 601 // NOTE: doesn't handle DYNAMIC values
todotani 1:6078e430af82 602 //
todotani 1:6078e430af82 603 static uint16_t handle_read_by_group_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
todotani 1:6078e430af82 604 uint16_t start_handle, uint16_t end_handle,
todotani 1:6078e430af82 605 uint16_t attribute_type_len, uint8_t * attribute_type){
todotani 1:6078e430af82 606
todotani 6:cf06ba884429 607 log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size);
todotani 1:6078e430af82 608 hexdump2(attribute_type, attribute_type_len);
todotani 1:6078e430af82 609
todotani 1:6078e430af82 610 uint16_t offset = 1;
todotani 1:6078e430af82 611 uint16_t pair_len = 0;
todotani 1:6078e430af82 612 uint16_t in_group = 0;
todotani 1:6078e430af82 613 uint16_t group_start_handle = 0;
todotani 1:6078e430af82 614 uint8_t const * group_start_value = NULL;
todotani 1:6078e430af82 615 uint16_t prev_handle = 0;
todotani 1:6078e430af82 616
todotani 1:6078e430af82 617 att_iterator_t it;
todotani 1:6078e430af82 618 att_iterator_init(&it);
todotani 1:6078e430af82 619 while (att_iterator_has_next(&it)){
todotani 1:6078e430af82 620 att_iterator_fetch_next(&it);
todotani 1:6078e430af82 621
todotani 1:6078e430af82 622 if (it.handle && it.handle < start_handle) continue;
todotani 1:6078e430af82 623 if (it.handle > end_handle) break; // (1)
todotani 1:6078e430af82 624
todotani 1:6078e430af82 625 // close current tag, if within a group and a new service definition starts or we reach end of att db
todotani 1:6078e430af82 626 if (in_group &&
todotani 1:6078e430af82 627 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
todotani 1:6078e430af82 628 // TODO: check if handle is included in start/end range
todotani 6:cf06ba884429 629 // log_debug("End of group, handle 0x%04x, val_len: %u\n", prev_handle, pair_len - 4);
todotani 1:6078e430af82 630
todotani 1:6078e430af82 631 bt_store_16(response_buffer, offset, group_start_handle);
todotani 1:6078e430af82 632 offset += 2;
todotani 1:6078e430af82 633 bt_store_16(response_buffer, offset, prev_handle);
todotani 1:6078e430af82 634 offset += 2;
todotani 1:6078e430af82 635 memcpy(response_buffer + offset, group_start_value, pair_len - 4);
todotani 1:6078e430af82 636 offset += pair_len - 4;
todotani 1:6078e430af82 637 in_group = 0;
todotani 1:6078e430af82 638
todotani 1:6078e430af82 639 // check if space for another handle pair available
todotani 1:6078e430af82 640 if (offset + pair_len > response_buffer_size){
todotani 1:6078e430af82 641 break;
todotani 1:6078e430af82 642 }
todotani 1:6078e430af82 643 }
todotani 1:6078e430af82 644
todotani 1:6078e430af82 645 // keep track of previous handle
todotani 1:6078e430af82 646 prev_handle = it.handle;
todotani 1:6078e430af82 647
todotani 1:6078e430af82 648 // does current attribute match
todotani 6:cf06ba884429 649 // log_debug("compare: %04x == %04x\n", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid);
todotani 1:6078e430af82 650 if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) {
todotani 1:6078e430af82 651
todotani 1:6078e430af82 652 // check if value has same len as last one
todotani 1:6078e430af82 653 uint16_t this_pair_len = 4 + it.value_len;
todotani 1:6078e430af82 654 if (offset > 1){
todotani 1:6078e430af82 655 if (this_pair_len != pair_len) {
todotani 1:6078e430af82 656 break;
todotani 1:6078e430af82 657 }
todotani 1:6078e430af82 658 }
todotani 1:6078e430af82 659
todotani 6:cf06ba884429 660 // log_debug("Begin of group, handle 0x%04x\n", it.handle);
todotani 1:6078e430af82 661
todotani 1:6078e430af82 662 // first
todotani 1:6078e430af82 663 if (offset == 1) {
todotani 1:6078e430af82 664 pair_len = this_pair_len;
todotani 1:6078e430af82 665 response_buffer[offset] = this_pair_len;
todotani 1:6078e430af82 666 offset++;
todotani 1:6078e430af82 667 }
todotani 1:6078e430af82 668
todotani 1:6078e430af82 669 group_start_handle = it.handle;
todotani 1:6078e430af82 670 group_start_value = it.value;
todotani 1:6078e430af82 671 in_group = 1;
todotani 1:6078e430af82 672 }
todotani 1:6078e430af82 673 }
todotani 1:6078e430af82 674
todotani 1:6078e430af82 675 if (offset == 1){
todotani 1:6078e430af82 676 return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST, start_handle);
todotani 1:6078e430af82 677 }
todotani 1:6078e430af82 678
todotani 1:6078e430af82 679 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
todotani 1:6078e430af82 680 return offset;
todotani 1:6078e430af82 681 }
todotani 1:6078e430af82 682 uint16_t handle_read_by_group_type_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 683 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 684 int attribute_type_len;
todotani 1:6078e430af82 685 if (request_len <= 7){
todotani 1:6078e430af82 686 attribute_type_len = 2;
todotani 1:6078e430af82 687 } else {
todotani 1:6078e430af82 688 attribute_type_len = 16;
todotani 1:6078e430af82 689 }
todotani 1:6078e430af82 690 return handle_read_by_group_type_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
todotani 1:6078e430af82 691 }
todotani 1:6078e430af82 692
todotani 1:6078e430af82 693 //
todotani 1:6078e430af82 694 // MARK: ATT_WRITE_REQUEST 0x12
todotani 1:6078e430af82 695 static uint16_t handle_write_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 696 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 697 uint16_t handle = READ_BT_16(request_buffer, 1);
todotani 1:6078e430af82 698 if (!att_write_callback) {
todotani 1:6078e430af82 699 // TODO: Use "Write Not Permitted"
todotani 1:6078e430af82 700 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
todotani 1:6078e430af82 701 }
todotani 1:6078e430af82 702 att_iterator_t it;
todotani 1:6078e430af82 703 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 704 if (!ok) {
todotani 1:6078e430af82 705 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
todotani 1:6078e430af82 706 }
todotani 1:6078e430af82 707 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
todotani 1:6078e430af82 708 // TODO: Use "Write Not Permitted"
todotani 1:6078e430af82 709 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
todotani 1:6078e430af82 710 }
todotani 1:6078e430af82 711 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL);
todotani 1:6078e430af82 712 response_buffer[0] = ATT_WRITE_RESPONSE;
todotani 1:6078e430af82 713 return 1;
todotani 1:6078e430af82 714 }
todotani 1:6078e430af82 715
todotani 1:6078e430af82 716 //
todotani 1:6078e430af82 717 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16
todotani 1:6078e430af82 718 static uint16_t handle_prepare_write_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 719 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 720 uint16_t handle = READ_BT_16(request_buffer, 1);
todotani 1:6078e430af82 721 if (!att_write_callback) {
todotani 1:6078e430af82 722 // TODO: Use "Write Not Permitted"
todotani 1:6078e430af82 723 return setup_error_atribute_not_found(response_buffer, ATT_PREPARE_WRITE_REQUEST, handle);
todotani 1:6078e430af82 724 }
todotani 1:6078e430af82 725 att_iterator_t it;
todotani 1:6078e430af82 726 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 727 if (!ok) {
todotani 1:6078e430af82 728 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
todotani 1:6078e430af82 729 }
todotani 1:6078e430af82 730 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
todotani 1:6078e430af82 731 // TODO: Use "Write Not Permitted"
todotani 1:6078e430af82 732 return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
todotani 1:6078e430af82 733 }
todotani 1:6078e430af82 734 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, 0, request_buffer + 3, request_len - 3, NULL);
todotani 1:6078e430af82 735
todotani 1:6078e430af82 736 // response: echo request
todotani 1:6078e430af82 737 memcpy(response_buffer, request_buffer, request_len);
todotani 1:6078e430af82 738 response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE;
todotani 1:6078e430af82 739 return request_len;
todotani 1:6078e430af82 740 }
todotani 1:6078e430af82 741
todotani 1:6078e430af82 742 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
todotani 1:6078e430af82 743 static uint16_t handle_execute_write_request(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 744 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 745 if (!att_write_callback) {
todotani 1:6078e430af82 746 // TODO: Use "Write Not Permitted"
todotani 1:6078e430af82 747 return setup_error_atribute_not_found(response_buffer, ATT_EXECUTE_WRITE_REQUEST, 0);
todotani 1:6078e430af82 748 }
todotani 1:6078e430af82 749 if (request_buffer[1]) {
todotani 1:6078e430af82 750 (*att_write_callback)(0, ATT_TRANSACTION_MODE_EXECUTE, 0, request_buffer + 3, request_len - 3, NULL);
todotani 1:6078e430af82 751 } else {
todotani 1:6078e430af82 752 (*att_write_callback)(0, ATT_TRANSACTION_MODE_CANCEL, 0, request_buffer + 3, request_len - 3, NULL);
todotani 1:6078e430af82 753 }
todotani 1:6078e430af82 754 response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE;
todotani 1:6078e430af82 755 return 1;
todotani 1:6078e430af82 756 }
todotani 1:6078e430af82 757
todotani 1:6078e430af82 758 // MARK: ATT_WRITE_COMMAND 0x52
todotani 1:6078e430af82 759 static void handle_write_command(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 760 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 761 if (!att_write_callback) return;
todotani 1:6078e430af82 762 uint16_t handle = READ_BT_16(request_buffer, 1);
todotani 1:6078e430af82 763 att_iterator_t it;
todotani 1:6078e430af82 764 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 765 if (!ok) return;
todotani 1:6078e430af82 766 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
todotani 1:6078e430af82 767 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL);
todotani 1:6078e430af82 768 }
todotani 1:6078e430af82 769
todotani 1:6078e430af82 770 // MARK: ATT_SIGNED_WRITE_COMAND 0xD2
todotani 1:6078e430af82 771 static void handle_signed_write_command(uint8_t * request_buffer, uint16_t request_len,
todotani 1:6078e430af82 772 uint8_t * response_buffer, uint16_t response_buffer_size){
todotani 1:6078e430af82 773
todotani 1:6078e430af82 774 if (request_len < 15) return;
todotani 1:6078e430af82 775 if (!att_write_callback) return;
todotani 1:6078e430af82 776 uint16_t handle = READ_BT_16(request_buffer, 1);
todotani 1:6078e430af82 777 att_iterator_t it;
todotani 1:6078e430af82 778 int ok = att_find_handle(&it, handle);
todotani 1:6078e430af82 779 if (!ok) return;
todotani 1:6078e430af82 780 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
todotani 1:6078e430af82 781 (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3 - 12, (signature_t *) request_buffer + request_len - 12);
todotani 1:6078e430af82 782 }
todotani 1:6078e430af82 783
todotani 1:6078e430af82 784 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION
todotani 1:6078e430af82 785 static uint16_t prepare_handle_value(att_connection_t * att_connection,
todotani 1:6078e430af82 786 uint16_t handle,
todotani 1:6078e430af82 787 uint8_t *value,
todotani 1:6078e430af82 788 uint16_t value_len,
todotani 1:6078e430af82 789 uint8_t * response_buffer){
todotani 1:6078e430af82 790 bt_store_16(response_buffer, 1, handle);
todotani 1:6078e430af82 791 if (value_len > att_connection->mtu - 3){
todotani 1:6078e430af82 792 value_len = att_connection->mtu - 3;
todotani 1:6078e430af82 793 }
todotani 1:6078e430af82 794 memcpy(&response_buffer[3], value, value_len);
todotani 1:6078e430af82 795 return value_len + 3;
todotani 1:6078e430af82 796 }
todotani 1:6078e430af82 797
todotani 1:6078e430af82 798 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b
todotani 1:6078e430af82 799 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
todotani 1:6078e430af82 800 uint16_t handle,
todotani 1:6078e430af82 801 uint8_t *value,
todotani 1:6078e430af82 802 uint16_t value_len,
todotani 1:6078e430af82 803 uint8_t * response_buffer){
todotani 1:6078e430af82 804
todotani 1:6078e430af82 805 response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION;
todotani 1:6078e430af82 806 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
todotani 1:6078e430af82 807 }
todotani 1:6078e430af82 808
todotani 1:6078e430af82 809 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d
todotani 1:6078e430af82 810 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
todotani 1:6078e430af82 811 uint16_t handle,
todotani 1:6078e430af82 812 uint8_t *value,
todotani 1:6078e430af82 813 uint16_t value_len,
todotani 1:6078e430af82 814 uint8_t * response_buffer){
todotani 1:6078e430af82 815
todotani 1:6078e430af82 816 response_buffer[0] = ATT_HANDLE_VALUE_INDICATION;
todotani 1:6078e430af82 817 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
todotani 1:6078e430af82 818 }
todotani 1:6078e430af82 819
todotani 1:6078e430af82 820 // MARK: Dispatcher
todotani 1:6078e430af82 821 uint16_t att_handle_request(att_connection_t * att_connection,
todotani 1:6078e430af82 822 uint8_t * request_buffer,
todotani 1:6078e430af82 823 uint16_t request_len,
todotani 1:6078e430af82 824 uint8_t * response_buffer){
todotani 1:6078e430af82 825 uint16_t response_len = 0;
todotani 1:6078e430af82 826 uint16_t response_buffer_size = att_connection->mtu;
todotani 1:6078e430af82 827
todotani 1:6078e430af82 828 switch (request_buffer[0]){
todotani 1:6078e430af82 829 case ATT_EXCHANGE_MTU_REQUEST:
todotani 1:6078e430af82 830 response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer);
todotani 1:6078e430af82 831 break;
todotani 1:6078e430af82 832 case ATT_FIND_INFORMATION_REQUEST:
todotani 1:6078e430af82 833 response_len = handle_find_information_request(request_buffer, request_len,response_buffer, response_buffer_size);
todotani 1:6078e430af82 834 break;
todotani 1:6078e430af82 835 case ATT_FIND_BY_TYPE_VALUE_REQUEST:
todotani 1:6078e430af82 836 response_len = handle_find_by_type_value_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 837 break;
todotani 1:6078e430af82 838 case ATT_READ_BY_TYPE_REQUEST:
todotani 1:6078e430af82 839 response_len = handle_read_by_type_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 840 break;
todotani 1:6078e430af82 841 case ATT_READ_REQUEST:
todotani 1:6078e430af82 842 response_len = handle_read_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 843 break;
todotani 1:6078e430af82 844 case ATT_READ_BLOB_REQUEST:
todotani 1:6078e430af82 845 response_len = handle_read_blob_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 846 break;
todotani 1:6078e430af82 847 case ATT_READ_MULTIPLE_REQUEST:
todotani 1:6078e430af82 848 response_len = handle_read_multiple_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 849 break;
todotani 1:6078e430af82 850 case ATT_READ_BY_GROUP_TYPE_REQUEST:
todotani 1:6078e430af82 851 response_len = handle_read_by_group_type_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 852 break;
todotani 1:6078e430af82 853 case ATT_WRITE_REQUEST:
todotani 1:6078e430af82 854 response_len = handle_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 855 break;
todotani 1:6078e430af82 856 case ATT_PREPARE_WRITE_REQUEST:
todotani 1:6078e430af82 857 response_len = handle_prepare_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 858 break;
todotani 1:6078e430af82 859 case ATT_EXECUTE_WRITE_REQUEST:
todotani 1:6078e430af82 860 response_len = handle_execute_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 861 break;
todotani 1:6078e430af82 862 case ATT_WRITE_COMMAND:
todotani 1:6078e430af82 863 handle_write_command(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 864 break;
todotani 1:6078e430af82 865 case ATT_SIGNED_WRITE_COMAND:
todotani 1:6078e430af82 866 handle_signed_write_command(request_buffer, request_len, response_buffer, response_buffer_size);
todotani 1:6078e430af82 867 break;
todotani 1:6078e430af82 868 default:
todotani 6:cf06ba884429 869 log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]);
todotani 1:6078e430af82 870 hexdump2(&request_buffer[9], request_len-9);
todotani 1:6078e430af82 871 break;
todotani 1:6078e430af82 872 }
todotani 1:6078e430af82 873 return response_len;
todotani 1:6078e430af82 874 }
todotani 1:6078e430af82 875
todotani 1:6078e430af82 876 #if 0
todotani 1:6078e430af82 877
todotani 1:6078e430af82 878 // test profile
todotani 1:6078e430af82 879 #include "profile.h"
todotani 1:6078e430af82 880
todotani 1:6078e430af82 881 int main(){
todotani 1:6078e430af82 882 int acl_buffer_size;
todotani 1:6078e430af82 883 uint8_t acl_buffer[27];
todotani 1:6078e430af82 884 att_set_db(profile_data);
todotani 1:6078e430af82 885 att_dump_attributes();
todotani 1:6078e430af82 886
todotani 1:6078e430af82 887 uint8_t uuid_1[] = { 0x00, 0x18};
todotani 1:6078e430af82 888 acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
todotani 1:6078e430af82 889 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 890
todotani 1:6078e430af82 891 uint8_t uuid_3[] = { 0x00, 0x2a};
todotani 1:6078e430af82 892 acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3);
todotani 1:6078e430af82 893 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 894
todotani 1:6078e430af82 895 acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
todotani 1:6078e430af82 896 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 897
todotani 1:6078e430af82 898 uint8_t uuid_4[] = { 0x00, 0x28};
todotani 1:6078e430af82 899 acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4);
todotani 1:6078e430af82 900 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 901
todotani 1:6078e430af82 902 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff);
todotani 1:6078e430af82 903 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 904 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff);
todotani 1:6078e430af82 905 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 906 acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff);
todotani 1:6078e430af82 907 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 908
todotani 1:6078e430af82 909 acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003);
todotani 1:6078e430af82 910 hexdump2(acl_buffer, acl_buffer_size);
todotani 1:6078e430af82 911
todotani 1:6078e430af82 912 return 0;
todotani 1:6078e430af82 913 }
todotani 1:6078e430af82 914 #endif