// ATT Client Read Callback for Dynamic Data // - if buffer == NULL, don't copy data, just return size of value // - if buffer != NULL, copy data and return number bytes copied // @param offset defines start of attribute value static uint16_t att_read_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ printf("READ Callback, handle %04x, offset %u, buffer size %u\n", handle, offset, buffer_size); uint16_t att_value_len; uint16_t uuid16 = att_uuid_for_handle(handle); switch (uuid16){ case 0x2902: if (buffer) { buffer[0] = client_configuration; } return 1; case 0x2a00: att_value_len = strlen(gap_device_name); if (buffer) { memcpy(buffer, gap_device_name, att_value_len); } return att_value_len; case 0x2a01: if (buffer){ bt_store_16(buffer, 0, gap_appearance); } return 2; case 0x2a02: if (buffer){ buffer[0] = gap_privacy; } return 1; case 0x2A03: if (buffer) { bt_flip_addr(buffer, gap_reconnection_address); } return 6; // handle device name // handle appearance default: break; } // find attribute int index = att_attribute_for_handle(handle); uint8_t * att_value; if (index < 0){ // not written before if (att_default_value_long){ att_value = (uint8_t*) default_value_long; att_value_len = strlen(default_value_long); } else { att_value = (uint8_t*) default_value_short; att_value_len = strlen(default_value_short); } } else { att_value = att_attributes[index].value; att_value_len = att_attributes[index].len; } printf("Attribute len %u, data: ", att_value_len); printf_hexdump(att_value, att_value_len); // assert offset <= att_value_len if (offset > att_value_len) { return 0; } uint16_t bytes_to_copy = att_value_len - offset; if (!buffer) return bytes_to_copy; if (bytes_to_copy > buffer_size){ bytes_to_copy = buffer_size; } memcpy(buffer, &att_value[offset], bytes_to_copy); return bytes_to_copy; }
// write requests static int att_write_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ printf("WRITE Callback, handle %04x, mode %u, offset %u, data: ", handle, transaction_mode, offset); printf_hexdump(buffer, buffer_size); uint16_t uuid16 = att_uuid_for_handle(handle); switch (uuid16){ case 0x2902: client_configuration = buffer[0]; client_configuration_handle = handle; printf("Client Configuration set to %u for handle %04x\n", client_configuration, handle); return 0; // ok case 0x2a00: memcpy(gap_device_name, buffer, buffer_size); gap_device_name[buffer_size]=0; printf("Setting device name to '%s'\n", gap_device_name); return 0; case 0x2a01: gap_appearance = READ_BT_16(buffer, 0); printf("Setting appearance to 0x%04x'\n", gap_appearance); return 0; case 0x2a02: gap_privacy = buffer[0]; printf("Setting privacy to 0x%04x'\n", gap_privacy); update_advertisements(); return 0; case 0x2A03: bt_flip_addr(gap_reconnection_address, buffer); printf("Setting Reconnection Address to %s\n", bd_addr_to_str(gap_reconnection_address)); return 0; // handle device name // handle appearance } // check transaction mode int attributes_index; int writes_index; switch (transaction_mode){ case ATT_TRANSACTION_MODE_NONE: attributes_index = att_attribute_for_handle(handle); if (attributes_index < 0){ attributes_index = att_attribute_for_handle(0); if (attributes_index < 0) return 0; // ok, but we couldn't store it (our fault) att_attributes[attributes_index].handle = handle; // not written before uint8_t * att_value; uint16_t att_value_len; if (att_default_value_long){ att_value = (uint8_t*) default_value_long; att_value_len = strlen(default_value_long); } else { att_value = (uint8_t*) default_value_short; att_value_len = strlen(default_value_short); } att_attributes[attributes_index].len = att_value_len; } if (buffer_size > att_attributes[attributes_index].len) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; att_attributes[attributes_index].len = buffer_size; memcpy(att_attributes[attributes_index].value, buffer, buffer_size); break; case ATT_TRANSACTION_MODE_ACTIVE: writes_index = att_write_queue_for_handle(handle); if (writes_index < 0) return ATT_ERROR_PREPARE_QUEUE_FULL; if (offset > att_write_queues[writes_index].len) return ATT_ERROR_INVALID_OFFSET; if (buffer_size + offset > ATT_VALUE_MAX_LEN) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; att_write_queues[writes_index].len = buffer_size + offset; memcpy(&(att_write_queues[writes_index].value[offset]), buffer, buffer_size); break; case ATT_TRANSACTION_MODE_EXECUTE: for (writes_index=0 ; writes_index<ATT_NUM_WRITE_QUEUES ; writes_index++){ handle = att_write_queues[writes_index].handle; if (handle == 0) continue; attributes_index = att_attribute_for_handle(handle); if (attributes_index < 0){ attributes_index = att_attribute_for_handle(0); if (attributes_index < 0) continue; att_attributes[attributes_index].handle = handle; } att_attributes[attributes_index].len = att_write_queues[writes_index].len; memcpy(att_attributes[attributes_index].value, att_write_queues[writes_index].value, att_write_queues[writes_index].len); } att_write_queue_init(); break; case ATT_TRANSACTION_MODE_CANCEL: att_write_queue_init(); break; } return 0; }
// ATT Client Read Callback for Dynamic Data // - if buffer == NULL, don't copy data, just return size of value // - if buffer != NULL, copy data and return number bytes copied // @param offset defines start of attribute value static uint16_t att_read_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ printf("READ Callback, handle %04x, offset %u, buffer size %u\n", attribute_handle, offset, buffer_size); uint16_t att_value_len; switch (attribute_handle){ case ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE: att_value_len = strlen(gap_device_name); if (buffer) { memcpy(buffer, gap_device_name, att_value_len); } return att_value_len; case ATT_CHARACTERISTIC_GAP_APPEARANCE_01_VALUE_HANDLE: if (buffer){ bt_store_16(buffer, 0, gap_appearance); } return 2; case ATT_CHARACTERISTIC_GAP_PERIPHERAL_PRIVACY_FLAG_01_VALUE_HANDLE: if (buffer){ buffer[0] = gap_privacy; } return 1; case ATT_CHARACTERISTIC_GAP_RECONNECTION_ADDRESS_01_VALUE_HANDLE: if (buffer) { bt_flip_addr(buffer, gap_reconnection_address); } return 6; default: break; } uint16_t uuid16 = att_uuid_for_handle(handle); if (uuid16){ printf("Resolved to UUID %04x\n", uuid16); switch (uuid16){ case 0x2902: if (buffer) { buffer[0] = client_configuration; } return 1; default: break; } } // find attribute int index = att_attribute_for_handle(handle); uint8_t * att_value; if (index < 0){ // not written before if (att_default_value_long){ att_value = (uint8_t*) default_value_long; att_value_len = strlen(default_value_long); } else { att_value = (uint8_t*) default_value_short; att_value_len = strlen(default_value_short); } } else { att_value = att_attributes[index].value; att_value_len = att_attributes[index].len; } printf("Attribute len %u, data: ", att_value_len); printf_hexdump(att_value, att_value_len); // assert offset <= att_value_len if (offset > att_value_len) { return 0; } uint16_t bytes_to_copy = att_value_len - offset; if (!buffer) return bytes_to_copy; if (bytes_to_copy > buffer_size){ bytes_to_copy = buffer_size; } memcpy(buffer, &att_value[offset], bytes_to_copy); return bytes_to_copy; }