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

Files at this revision

API Documentation at this revision

Comitter:
todotani
Date:
Thu Feb 07 14:01:01 2013 +0000
Parent:
0:1ed23ab1345f
Child:
2:24b33d92e086
Commit message:
BLE demo for mbed; Ported SBDBT (RunningElectronics) firmware for BLE to mbed. It can communicate with iOS

Changed in this revision

BLE_demo.cpp Show annotated file Show diff for this revision Revisions of this file
BTstack/att.c Show annotated file Show diff for this revision Revisions of this file
BTstack/att.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/run_loop.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/sdp_util.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack_memory.c Show annotated file Show diff for this revision Revisions of this file
BTstack/config.h Show annotated file Show diff for this revision Revisions of this file
BTstack/global.h Show annotated file Show diff for this revision Revisions of this file
BTstack/hci.c Show annotated file Show diff for this revision Revisions of this file
BTstack/memory_pool.c Show annotated file Show diff for this revision Revisions of this file
BTstack/profile.h Show annotated file Show diff for this revision Revisions of this file
BTstack/rfcomm.c Show diff for this revision Revisions of this file
BTstack/rfcomm.h Show annotated file Show diff for this revision Revisions of this file
BTstack/run_loop_embedded.c Show annotated file Show diff for this revision Revisions of this file
BTstack/run_loop_private.h Show annotated file Show diff for this revision Revisions of this file
BTstack/sdp.c Show diff for this revision Revisions of this file
BTstack/sdp.h Show diff for this revision Revisions of this file
BTstack/sdp_util.c Show diff for this revision Revisions of this file
led_counter.cpp Show diff for this revision Revisions of this file
mouse_demo.cpp Show diff for this revision Revisions of this file
spp_counter.cpp Show diff for this revision Revisions of this file
spp_demo.cpp Show diff for this revision Revisions of this file
spp_flowcontrol.cpp Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_demo.cpp	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,302 @@
+/*
+ * BLE_demo
+ */
+
+// mbed specific
+#include "mbed.h"
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2), led3(LED3);
+
+#define HEARTBEAT_PERIOD_MS 500
+
+// from btstack ble_server.c
+#include "global.h"
+#include "debug.h"
+#include "btstack/btstack.h"
+#include "btstack/hci_cmds.h"
+#include "btstack/run_loop.h"
+
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "config.h"
+
+#include "att.h"
+
+unsigned    timer_counter=0;
+uint8_t     startup_state=0;
+
+
+hci_transport_t * hci_transport_picusb_instance();
+
+static att_connection_t att_connection;
+static uint16_t         att_response_handle = 0;
+static uint16_t         att_response_size   = 0;
+static uint8_t          att_response_buffer[28];
+
+uint8_t connection_status=0;
+
+void hexdump2(void *data, int size){
+    int i;
+    for (i=0; i<size;i++){
+        log_info("%02X ", ((uint8_t *)data)[i]);
+    }
+    log_info("\n");
+}
+
+static void att_try_respond(void){
+    if (!att_response_size) return;
+    if (!att_response_handle) return;
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) return;
+    
+    // update state before sending packet
+    uint16_t size = att_response_size;
+    att_response_size = 0;
+    l2cap_send_connectionless(att_response_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, att_response_buffer, size);
+}
+
+
+static void att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
+    if (packet_type != ATT_DATA_PACKET) return;
+    
+    att_response_handle = handle;
+    att_response_size = att_handle_request(&att_connection, packet, size, att_response_buffer);
+    att_try_respond();
+}
+
+
+// enable LE, setup ADV data
+static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    static bd_addr_t addr;
+//    uint8_t adv_data[] = { 02, 01, 05,   03, 02, 0xf0, 0xff }; 
+    const uint8_t adv_data[31]="\x02\x01\x05" "\x06\x09SBDBT";
+    switch (packet_type) {
+            
+        case HCI_EVENT_PACKET:
+            switch (packet[0]) {
+                
+                case BTSTACK_EVENT_STATE:
+                    // bt stack activated, get started - set local name
+                    if (packet[2] == HCI_STATE_WORKING) {
+                       log_info("Working!\n");
+                        hci_send_cmd(&hci_read_local_supported_features);
+                    }
+                    break;
+                
+                case DAEMON_EVENT_HCI_PACKET_SENT:
+                    att_try_respond();
+                    break;
+                    
+                case HCI_EVENT_LE_META:
+                    switch (packet[2]) {
+                        case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+                            // reset connection MTU
+                            att_connection.mtu = 23;
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+
+                case BTSTACK_EVENT_NR_CONNECTIONS_CHANGED:
+                    if (packet[2]) {
+                        connection_status=1;
+                        log_info("CONNECTED\n");
+                    } else {
+                        connection_status=0;
+                        log_info("NOT CONNECTED\n");
+                    }
+                    break;
+                    
+                case HCI_EVENT_DISCONNECTION_COMPLETE:
+                    att_response_handle =0;
+                    att_response_size = 0;
+                    
+                    // restart advertising
+                    hci_send_cmd(&hci_le_set_advertise_enable, 1);
+                    break;
+                    
+                case HCI_EVENT_COMMAND_COMPLETE:
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
+                        bt_flip_addr(addr, &packet[6]);
+                        log_info("BD ADDR: %s\n", bd_addr_to_str(addr));
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_local_supported_features)){
+                        log_info("Local supported features: %04lX%04lX\n", READ_BT_32(packet, 10), READ_BT_32(packet, 6));
+                        hci_send_cmd(&hci_set_event_mask, 0xffffffff, 0x20001fff);
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_set_event_mask)){
+                        hci_send_cmd(&hci_write_le_host_supported, 1, 1);
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_le_host_supported)){
+                        hci_send_cmd(&hci_le_set_event_mask, 0xffffffff, 0xffffffff);
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_event_mask)){
+                        hci_send_cmd(&hci_le_read_buffer_size);
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_read_buffer_size)){
+                        log_info("LE buffer size: %u, count %u\n", READ_BT_16(packet,6), packet[8]);
+                       hci_send_cmd(&hci_le_read_supported_states);
+                       break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_read_supported_states)){
+                       hci_send_cmd(&hci_le_set_advertising_parameters,  0x0400, 0x0800, 0, 0, 0, &addr, 0x07, 0);
+                       break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_parameters)){
+                       hci_send_cmd(&hci_le_set_advertising_data, sizeof(adv_data), adv_data);
+                       break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_data)){
+                       hci_send_cmd(&hci_le_set_scan_response_data, 10, adv_data);
+                       break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_scan_response_data)){
+                       hci_send_cmd(&hci_le_set_advertise_enable, 1);
+                       break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertise_enable)){
+                        hci_discoverable_control(1);
+                        log_info("startup_state=1\n");
+                        startup_state=1;
+                        led1 = 0;
+                        break;
+                    }
+                    
+            }
+    }
+}
+
+// test profile
+#include "profile.h"
+
+static uint8_t strbuf[80];
+static uint8_t  ledvalue;
+
+// read requests
+static uint16_t att_read_callback(uint16_t handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
+    uint16_t    ret=0,val;
+
+    if(buffer){
+        log_info("READ Callback, handle %04x\n", handle);
+        led1 = 1;
+    }
+    switch(handle){
+       case 0x000b:
+            ret=strlen((char*)strbuf);
+            if(buffer && ret<=buffer_size){
+                log_info("Read text: %s\n", strbuf);
+                memcpy(buffer,strbuf,ret);
+            }
+            break;
+        case 0x000d:
+            if(buffer && buffer_size){
+                log_info("Read value: %u\n", buffer[0]);
+                buffer[0]=ledvalue;
+            }
+            ret=1;
+            break;
+        case 0x000f:
+            if(buffer && buffer_size>=2){
+                val=timer_counter;
+                log_info("Read value: %u\n", val);
+                buffer[0]=val&0xff;
+                buffer[1]=val>>8;
+            }
+            ret=2;
+            break;
+    }
+    return ret;
+}
+
+// write requests
+static void att_write_callback(uint16_t handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size, signature_t * signature){
+    log_info("WRITE Callback, handle %04x\n", handle);
+    led1 = 1;
+    switch(handle){
+        case 0x000b:
+            buffer[buffer_size]=0;
+            if(sizeof(strbuf)>buffer_size){
+                strcpy((char*)strbuf,(char*)buffer);
+            }
+            log_info("New text: %s\n", buffer);
+            break;
+        case 0x000d:
+            log_info("New value: %u\n", buffer[0]);
+            ledvalue=buffer[0];
+            if (buffer[0]){
+                led1 = 1;
+            } else {
+                led1 = 0;
+            }
+            break;
+    }
+}
+
+
+static void  heartbeat_handler(struct timer *ts){
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+    led2 = !led2;
+} 
+
+
+// main
+int main(void)
+{
+    pc.baud(115200);
+    log_info("%s\n", __FILE__);
+
+    // init LEDs
+    led1 = led2 = led3 = 1;
+    
+   /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    
+    // init HCI
+    // use BlueUSB
+    hci_transport_t* transport = hci_transport_usb_instance();
+    bt_control_t       * control   = NULL;
+    hci_uart_config_t  * config    = NULL;
+    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
+    hci_init(transport, config, control, remote_db);
+    
+    // use eHCILL
+    // bt_control_cc256x_enable_ehcill(1);
+    
+    // set up l2cap_le
+    l2cap_init();
+    l2cap_register_fixed_channel(att_packet_handler, L2CAP_CID_ATTRIBUTE_PROTOCOL);
+    l2cap_register_packet_handler(packet_handler);
+    
+    // set up ATT
+    att_set_db(profile_data);
+    att_set_write_callback(att_write_callback);
+    att_set_read_callback(att_read_callback);
+    att_dump_attributes();
+    att_connection.mtu = 27;
+
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    log_info("Run...\n\r");
+
+    // turn on!
+    hci_power_control(HCI_POWER_ON);
+
+    // go!
+    run_loop_execute(); 
+    
+    // happy compiler!
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/att.c	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) 2011-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "att.h"
+
+// from src/utils.
+#define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
+
+// Buetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian
+static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
+    buffer[pos++] = value;
+    buffer[pos++] = value >> 8;
+}
+
+static void hexdump2(void const *data, int size){
+    int i;
+    for (i=0; i<size;i++){
+        printf("%02X ", ((uint8_t *)data)[i]);
+    }
+    printf("\n");
+}
+
+static void printUUID128(const uint8_t * uuid){
+    int i;
+    for (i=15; i >= 0 ; i--){
+        printf("%02X", uuid[i]);
+        switch (i){
+            case 4:
+            case 6:
+            case 8:
+            case 10:
+                printf("-");
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+static int is_Bluetooth_Base_UUID(uint8_t const *uuid){
+    if (memcmp(&uuid[0],  &bluetooth_base_uuid[0], 12)) return 0;
+    if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0;
+    return 1;
+    
+}
+
+// ATT Database
+static uint8_t const * att_db = NULL;
+static att_read_callback_t  att_read_callback  = NULL;
+static att_write_callback_t att_write_callback = NULL;
+
+// new java-style iterator
+typedef struct att_iterator {
+    // private
+    uint8_t const * att_ptr;
+    // public
+    uint16_t size;
+    uint16_t flags;
+    uint16_t handle;
+    uint8_t  const * uuid;
+    uint16_t value_len;
+    uint8_t  const * value;
+} att_iterator_t;
+
+void att_iterator_init(att_iterator_t *it){
+    it->att_ptr = att_db;
+}
+
+int att_iterator_has_next(att_iterator_t *it){
+    return it->att_ptr != NULL;
+}
+
+void att_iterator_fetch_next(att_iterator_t *it){
+    it->size   = READ_BT_16(it->att_ptr, 0);
+    if (it->size == 0){
+        it->flags = 0;
+        it->handle = 0;
+        it->uuid = NULL;
+        it->value_len = 0;
+        it->value = NULL;
+        it->att_ptr = NULL;
+        return;
+    }
+    it->flags  = READ_BT_16(it->att_ptr, 2);
+    it->handle = READ_BT_16(it->att_ptr, 4);
+    it->uuid   = &it->att_ptr[6];
+    // handle 128 bit UUIDs
+    if (it->flags & ATT_PROPERTY_UUID128){
+        it->value_len = it->size - 22;
+        it->value  = &it->att_ptr[22];
+    } else {
+        it->value_len = it->size - 8;
+        it->value  = &it->att_ptr[8];
+    }
+    // advance AFTER setting values
+    it->att_ptr += it->size;
+}
+
+int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){
+    if (it->handle == 0) return 0;
+    if (it->flags & ATT_PROPERTY_UUID128){
+        if (!is_Bluetooth_Base_UUID(it->uuid)) return 0;
+        return READ_BT_16(it->uuid, 12) == uuid;
+    }
+    return READ_BT_16(it->uuid, 0)  == uuid;
+}
+
+int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){
+    if (it->handle == 0) return 0;
+    // input: UUID16
+    if (uuid_len == 2) {
+        return att_iterator_match_uuid16(it, READ_BT_16(uuid, 0));
+    }
+    // input and db: UUID128 
+    if (it->flags & ATT_PROPERTY_UUID128){
+        return memcmp(it->uuid, uuid, 16) == 0;
+    }
+    // input: UUID128, db: UUID16
+    if (!is_Bluetooth_Base_UUID(uuid)) return 0;
+    return READ_BT_16(uuid, 12) == READ_BT_16(it->uuid, 0);
+}
+
+
+int att_find_handle(att_iterator_t *it, uint16_t handle){
+    att_iterator_init(it);
+    while (att_iterator_has_next(it)){
+        att_iterator_fetch_next(it);
+        if (it->handle != handle) continue;
+        return 1;
+    }
+    return 0;
+}
+
+static void att_update_value_len(att_iterator_t *it){
+    if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0 || !att_read_callback) return;
+    it->value_len = (*att_read_callback)(it->handle, 0, NULL, 0);
+    return;
+}
+
+static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
+    
+    // DYNAMIC 
+    if ((it->flags & ATT_PROPERTY_DYNAMIC) && att_read_callback) {
+        return (*att_read_callback)(it->handle, offset, buffer, buffer_size);
+    }
+    
+    // STATIC
+    uint16_t bytes_to_copy = it->value_len;
+    if (bytes_to_copy > buffer_size){
+        bytes_to_copy = buffer_size;
+    }
+    memcpy(buffer, it->value, bytes_to_copy);
+    return bytes_to_copy;
+}
+
+void att_set_db(uint8_t const * db){
+    att_db = db;
+}
+
+void att_set_read_callback(att_read_callback_t callback){
+    att_read_callback = callback;
+}
+
+void att_set_write_callback(att_write_callback_t callback){
+    att_write_callback = callback;
+}
+
+void att_dump_attributes(void){
+    att_iterator_t it;
+    att_iterator_init(&it);
+    while (att_iterator_has_next(&it)){
+        att_iterator_fetch_next(&it);
+        if (it.handle == 0) {
+            printf("Handle: END\n");
+            return;
+        }
+        printf("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags);
+        if (it.flags & ATT_PROPERTY_UUID128){
+            printUUID128(it.uuid);
+        } else {
+            printf("%04x", READ_BT_16(it.uuid, 0));
+        }
+        printf(", value_len: %u, value: ", it.value_len);
+        hexdump2(it.value, it.value_len);
+    }
+}
+
+static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){
+    response_buffer[0] = ATT_ERROR_RESPONSE;
+    response_buffer[1] = request;
+    bt_store_16(response_buffer, 2, handle);
+    response_buffer[4] = error_code;
+    return 5;
+}
+
+static uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){
+    return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
+}
+
+static uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){
+    return setup_error(response_buffer, request, handle, ATT_ERROR_ATTRIBUTE_INVALID);
+}
+
+static uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){
+    return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET);
+}
+
+//
+// MARK: ATT_EXCHANGE_MTU_REQUEST
+//
+static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
+                                         uint8_t * response_buffer){
+
+    uint16_t client_rx_mtu = READ_BT_16(request_buffer, 1);
+    if (client_rx_mtu < att_connection->mtu){
+        att_connection->mtu = client_rx_mtu;
+    }
+    
+    response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE;
+    bt_store_16(response_buffer, 1, att_connection->mtu);
+    return 3;
+}
+
+
+//
+// MARK: ATT_FIND_INFORMATION_REQUEST
+//
+// TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
+//
+static uint16_t handle_find_information_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
+                                           uint16_t start_handle, uint16_t end_handle){
+    
+    printf("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X\n", start_handle, end_handle);
+    
+    uint16_t offset   = 1;
+    uint16_t pair_len = 0;
+    
+    att_iterator_t it;
+    att_iterator_init(&it);
+    while (att_iterator_has_next(&it)){
+        att_iterator_fetch_next(&it);
+        if (!it.handle) break;
+        if (it.handle > end_handle) break;
+        if (it.handle < start_handle) continue;
+        
+        att_update_value_len(&it);
+        
+        // printf("Handle 0x%04x\n", it.handle);
+        
+        // check if value has same len as last one
+        uint16_t this_pair_len = 2 + it.value_len;
+        if (offset > 1){
+            if (pair_len != this_pair_len) {
+                break;
+            }
+        }
+        
+        // first
+        if (offset == 1) {
+            pair_len = this_pair_len;
+            if (it.value_len == 2) {
+                response_buffer[offset] = 0x01; // format
+            } else {
+                response_buffer[offset] = 0x02;
+            }
+            offset++;
+        }
+        
+        // space?
+        if (offset + pair_len > response_buffer_size) {
+            if (offset > 2) break;
+            it.value_len = response_buffer_size - 4;
+        }
+        
+        // store
+        bt_store_16(response_buffer, offset, it.handle);
+        offset += 2;
+        uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
+        offset += bytes_copied;
+    }
+    
+    if (offset == 1){
+        return setup_error_atribute_not_found(response_buffer, ATT_FIND_INFORMATION_REQUEST, start_handle);
+    }
+    
+    response_buffer[0] = ATT_FIND_INFORMATION_REPLY;
+    return offset;
+}
+
+static uint16_t handle_find_information_request(uint8_t * request_buffer,  uint16_t request_len,
+                                         uint8_t * response_buffer, uint16_t response_buffer_size){
+    return handle_find_information_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3));
+}
+
+//
+// MARK: ATT_FIND_BY_TYPE_VALUE
+//
+// "Only attributes with attribute handles between and including the Starting Handle parameter
+// and the Ending Handle parameter that match the requested attri- bute type and the attribute
+// value that have sufficient permissions to allow reading will be returned" -> (1)
+//
+// TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
+//
+// NOTE: doesn't handle DYNAMIC values
+// NOTE: only supports 16 bit UUIDs
+// 
+static uint16_t handle_find_by_type_value_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
+                                           uint16_t start_handle, uint16_t end_handle,
+                                           uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){
+    
+    printf("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type);
+    hexdump2(attribute_value, attribute_len);
+    
+    uint16_t offset      = 1;
+    uint16_t in_group    = 0;
+    uint16_t prev_handle = 0;
+    
+    att_iterator_t it;
+    att_iterator_init(&it);
+    while (att_iterator_has_next(&it)){
+        att_iterator_fetch_next(&it);
+        
+        if (it.handle && it.handle < start_handle) continue;
+        if (it.handle > end_handle) break;  // (1)
+        
+        // close current tag, if within a group and a new service definition starts or we reach end of att db
+        if (in_group &&
+            (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
+            
+            printf("End of group, handle 0x%04x\n", prev_handle);
+            bt_store_16(response_buffer, offset, prev_handle);
+            offset += 2;
+            in_group = 0;
+            
+            // check if space for another handle pair available
+            if (offset + 4 > response_buffer_size){
+                break;
+            }
+        }
+        
+        // keep track of previous handle
+        prev_handle = it.handle;
+        
+        // does current attribute match
+        if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
+            printf("Begin of group, handle 0x%04x\n", it.handle);
+            bt_store_16(response_buffer, offset, it.handle);
+            offset += 2;
+            in_group = 1;
+        }
+    }
+    
+    if (offset == 1){
+        return setup_error_atribute_not_found(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST, start_handle);
+    }
+    
+    response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE;
+    return offset;
+}
+                                         
+static uint16_t handle_find_by_type_value_request(uint8_t * request_buffer,  uint16_t request_len,
+                                           uint8_t * response_buffer, uint16_t response_buffer_size){
+    int attribute_len = request_len - 7;
+    return handle_find_by_type_value_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1),
+                                              READ_BT_16(request_buffer, 3), READ_BT_16(request_buffer, 5), attribute_len, &request_buffer[7]);
+}
+                                                                                  
+//
+// MARK: ATT_READ_BY_TYPE_REQUEST
+//
+static uint16_t handle_read_by_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
+                                      uint16_t start_handle, uint16_t end_handle,
+                                      uint16_t attribute_type_len, uint8_t * attribute_type){
+    
+    printf("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); 
+    hexdump2(attribute_type, attribute_type_len);
+    
+    uint16_t offset   = 1;
+    uint16_t pair_len = 0;
+
+    att_iterator_t it;
+    att_iterator_init(&it);
+    while (att_iterator_has_next(&it)){
+        att_iterator_fetch_next(&it);
+        
+        if (!it.handle) break;
+        if (it.handle < start_handle) continue;
+        if (it.handle > end_handle) break;  // (1)
+
+        // does current attribute match
+        if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue;
+        
+        att_update_value_len(&it);
+        
+        // check if value has same len as last one
+        uint16_t this_pair_len = 2 + it.value_len;
+        if (offset > 1){
+            if (pair_len != this_pair_len) {
+                break;
+            }
+        }
+        
+        // first
+        if (offset == 1) {
+            pair_len = this_pair_len;
+            response_buffer[offset] = pair_len;
+            offset++;
+        }
+        
+        // space?
+        if (offset + pair_len > response_buffer_size) {
+            if (offset > 2) break;
+            it.value_len = response_buffer_size - 4;
+        }
+        
+        // store
+        bt_store_16(response_buffer, offset, it.handle);
+        offset += 2;
+        uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
+        offset += bytes_copied;
+    }
+    
+    if (offset == 1){
+        return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_TYPE_REQUEST, start_handle);
+    }
+    
+    response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE;
+    return offset;
+}
+
+static uint16_t handle_read_by_type_request(uint8_t * request_buffer,  uint16_t request_len,
+                                     uint8_t * response_buffer, uint16_t response_buffer_size){
+    int attribute_type_len;
+    if (request_len <= 7){
+        attribute_type_len = 2;
+    } else {
+        attribute_type_len = 16;
+    }
+    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]);
+}
+
+//
+// MARK: ATT_READ_BY_TYPE_REQUEST
+//
+static uint16_t handle_read_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){
+    
+    printf("ATT_READ_REQUEST: handle %04x\n", handle);
+    
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok){
+        return setup_error_atribute_not_found(response_buffer, ATT_READ_REQUEST, handle);
+    }
+    
+    att_update_value_len(&it);
+
+    uint16_t offset   = 1;
+    // limit data
+    if (offset + it.value_len > response_buffer_size) {
+        it.value_len = response_buffer_size - 1;
+    }
+    
+    // store
+    uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
+    offset += bytes_copied;
+    
+    response_buffer[0] = ATT_READ_RESPONSE;
+    return offset;
+}
+
+static uint16_t handle_read_request(uint8_t * request_buffer,  uint16_t request_len,
+                             uint8_t * response_buffer, uint16_t response_buffer_size){
+    return handle_read_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1));
+}
+
+//
+// MARK: ATT_READ_BLOB_REQUEST 0x0c
+//
+static uint16_t handle_read_blob_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){
+    printf("ATT_READ_BLOB_REQUEST: handle %04x, offset %u\n", handle, value_offset);
+
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok){
+        return setup_error_atribute_not_found(response_buffer, ATT_READ_BLOB_REQUEST, handle);
+    }
+    
+    att_update_value_len(&it);
+
+    if (value_offset >= it.value_len){
+        return setup_error_invalid_offset(response_buffer, ATT_READ_BLOB_REQUEST, handle);
+    }
+    
+    // limit data
+    uint16_t offset   = 1;
+    if (offset + it.value_len - value_offset > response_buffer_size) {
+        it.value_len = response_buffer_size - 1 + value_offset;
+    }
+    
+    // store
+    uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset);
+    offset += bytes_copied;
+    
+    response_buffer[0] = ATT_READ_BLOB_RESPONSE;
+    return offset;
+}
+
+uint16_t handle_read_blob_request(uint8_t * request_buffer,  uint16_t request_len,
+                                  uint8_t * response_buffer, uint16_t response_buffer_size){
+    return handle_read_blob_request2(response_buffer, response_buffer_size, READ_BT_16(request_buffer, 1), READ_BT_16(request_buffer, 3));
+}
+
+//
+// MARK: ATT_READ_MULTIPLE_REQUEST 0x0e
+//
+static uint16_t handle_read_multiple_request2(uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint16_t * handles){
+    printf("ATT_READ_MULTIPLE_REQUEST: num handles %u\n", num_handles);
+    
+    uint16_t offset   = 1;
+
+    int i;
+    for (i=0;i<num_handles;i++){
+        uint16_t handle = handles[i];
+        
+        if (handle == 0){
+            return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle);
+        }
+        
+        att_iterator_t it;
+
+        int ok = att_find_handle(&it, handle);
+        if (!ok){
+            return setup_error_invalid_handle(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle);
+        }
+
+        att_update_value_len(&it);
+        
+        // limit data
+        if (offset + it.value_len > response_buffer_size) {
+            it.value_len = response_buffer_size - 1;
+        }
+        
+        // store
+        uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len);
+        offset += bytes_copied;
+    }
+    
+    response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE;
+    return offset;
+}
+uint16_t handle_read_multiple_request(uint8_t * request_buffer,  uint16_t request_len,
+                                      uint8_t * response_buffer, uint16_t response_buffer_size){
+    int num_handles = (request_len - 1) >> 1;
+    return handle_read_multiple_request2(response_buffer, response_buffer_size, num_handles, (uint16_t*) &request_buffer[1]);
+}
+
+//
+// MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
+//
+// TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
+//
+// NOTE: doesn't handle DYNAMIC values
+//
+static uint16_t handle_read_by_group_type_request2(uint8_t * response_buffer, uint16_t response_buffer_size,
+                                            uint16_t start_handle, uint16_t end_handle,
+                                            uint16_t attribute_type_len, uint8_t * attribute_type){
+    
+    printf("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size);
+    hexdump2(attribute_type, attribute_type_len);
+    
+    uint16_t offset   = 1;
+    uint16_t pair_len = 0;
+    uint16_t in_group = 0;
+    uint16_t group_start_handle = 0;
+    uint8_t const * group_start_value = NULL;
+    uint16_t prev_handle = 0;
+
+    att_iterator_t it;
+    att_iterator_init(&it);
+    while (att_iterator_has_next(&it)){
+        att_iterator_fetch_next(&it);
+        
+        if (it.handle && it.handle < start_handle) continue;
+        if (it.handle > end_handle) break;  // (1)
+        
+        // close current tag, if within a group and a new service definition starts or we reach end of att db
+        if (in_group &&
+            (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
+            // TODO: check if handle is included in start/end range
+            // printf("End of group, handle 0x%04x, val_len: %u\n", prev_handle, pair_len - 4);
+            
+            bt_store_16(response_buffer, offset, group_start_handle);
+            offset += 2;
+            bt_store_16(response_buffer, offset, prev_handle);
+            offset += 2;
+            memcpy(response_buffer + offset, group_start_value, pair_len - 4);
+            offset += pair_len - 4;
+            in_group = 0;
+            
+            // check if space for another handle pair available
+            if (offset + pair_len > response_buffer_size){
+                break;
+            }
+        }
+        
+        // keep track of previous handle
+        prev_handle = it.handle;
+        
+        // does current attribute match
+        // printf("compare: %04x == %04x\n", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid);
+        if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) {
+            
+            // check if value has same len as last one
+            uint16_t this_pair_len = 4 + it.value_len;
+            if (offset > 1){
+                if (this_pair_len != pair_len) {
+                    break;
+                }
+            }
+            
+            // printf("Begin of group, handle 0x%04x\n", it.handle);
+            
+            // first
+            if (offset == 1) {
+                pair_len = this_pair_len;
+                response_buffer[offset] = this_pair_len;
+                offset++;
+            }
+            
+            group_start_handle = it.handle;
+            group_start_value  = it.value;
+            in_group = 1;
+        }
+    }        
+    
+    if (offset == 1){
+        return setup_error_atribute_not_found(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST, start_handle);
+    }
+    
+    response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
+    return offset;
+}
+uint16_t handle_read_by_group_type_request(uint8_t * request_buffer,  uint16_t request_len,
+                                           uint8_t * response_buffer, uint16_t response_buffer_size){
+    int attribute_type_len;
+    if (request_len <= 7){
+        attribute_type_len = 2;
+    } else {
+        attribute_type_len = 16;
+    }
+    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]);
+}
+
+//
+// MARK: ATT_WRITE_REQUEST 0x12
+static uint16_t handle_write_request(uint8_t * request_buffer,  uint16_t request_len,
+                              uint8_t * response_buffer, uint16_t response_buffer_size){
+    uint16_t handle = READ_BT_16(request_buffer, 1);
+    if (!att_write_callback) {
+        // TODO: Use "Write Not Permitted"
+        return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
+    }
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok) {
+        return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
+    }
+    if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
+        // TODO: Use "Write Not Permitted"
+        return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
+    }
+    (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL);
+    response_buffer[0] = ATT_WRITE_RESPONSE;
+    return 1;
+}
+
+//
+// MARK: ATT_PREPARE_WRITE_REQUEST 0x16
+static uint16_t handle_prepare_write_request(uint8_t * request_buffer,  uint16_t request_len,
+                                      uint8_t * response_buffer, uint16_t response_buffer_size){
+    uint16_t handle = READ_BT_16(request_buffer, 1);
+    if (!att_write_callback) {
+        // TODO: Use "Write Not Permitted"
+        return setup_error_atribute_not_found(response_buffer, ATT_PREPARE_WRITE_REQUEST, handle);
+    }
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok) {
+        return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
+    }
+    if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
+        // TODO: Use "Write Not Permitted"
+        return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle);
+    }
+    (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, 0, request_buffer + 3, request_len - 3, NULL);
+    
+    // response: echo request
+    memcpy(response_buffer, request_buffer, request_len);
+    response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE;
+    return request_len;
+}
+
+// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
+static uint16_t handle_execute_write_request(uint8_t * request_buffer,  uint16_t request_len,
+                                      uint8_t * response_buffer, uint16_t response_buffer_size){
+    if (!att_write_callback) {
+        // TODO: Use "Write Not Permitted"
+        return setup_error_atribute_not_found(response_buffer, ATT_EXECUTE_WRITE_REQUEST, 0);
+    }
+    if (request_buffer[1]) {
+        (*att_write_callback)(0, ATT_TRANSACTION_MODE_EXECUTE, 0, request_buffer + 3, request_len - 3, NULL);
+    } else {
+        (*att_write_callback)(0, ATT_TRANSACTION_MODE_CANCEL, 0, request_buffer + 3, request_len - 3, NULL);
+    }
+    response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE;
+    return 1;
+}
+
+// MARK: ATT_WRITE_COMMAND 0x52
+static void handle_write_command(uint8_t * request_buffer,  uint16_t request_len,
+                                           uint8_t * response_buffer, uint16_t response_buffer_size){
+    if (!att_write_callback) return;
+    uint16_t handle = READ_BT_16(request_buffer, 1);
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok) return;
+    if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
+    (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL);
+}
+
+// MARK: ATT_SIGNED_WRITE_COMAND 0xD2
+static void handle_signed_write_command(uint8_t * request_buffer,  uint16_t request_len,
+                                 uint8_t * response_buffer, uint16_t response_buffer_size){
+
+    if (request_len < 15) return;
+    if (!att_write_callback) return;
+    uint16_t handle = READ_BT_16(request_buffer, 1);
+    att_iterator_t it;
+    int ok = att_find_handle(&it, handle);
+    if (!ok) return;
+    if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
+    (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3 - 12, (signature_t *) request_buffer + request_len - 12);
+}
+
+// MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION
+static uint16_t prepare_handle_value(att_connection_t * att_connection,
+                                     uint16_t handle,
+                                     uint8_t *value,
+                                     uint16_t value_len, 
+                                     uint8_t * response_buffer){
+    bt_store_16(response_buffer, 1, handle);
+    if (value_len > att_connection->mtu - 3){
+        value_len = att_connection->mtu - 3;
+    }
+    memcpy(&response_buffer[3], value, value_len);
+    return value_len + 3;
+}
+
+// MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b
+uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
+                                               uint16_t handle,
+                                               uint8_t *value,
+                                               uint16_t value_len, 
+                                               uint8_t * response_buffer){
+
+    response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION;
+    return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
+}
+
+// MARK: ATT_HANDLE_VALUE_INDICATION 0x1d
+uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
+                                             uint16_t handle,
+                                             uint8_t *value,
+                                             uint16_t value_len, 
+                                             uint8_t * response_buffer){
+
+    response_buffer[0] = ATT_HANDLE_VALUE_INDICATION;
+    return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
+}
+    
+// MARK: Dispatcher
+uint16_t att_handle_request(att_connection_t * att_connection,
+                            uint8_t * request_buffer,
+                            uint16_t request_len,
+                            uint8_t * response_buffer){
+    uint16_t response_len = 0;
+    uint16_t response_buffer_size = att_connection->mtu;
+    
+    switch (request_buffer[0]){
+        case ATT_EXCHANGE_MTU_REQUEST:
+            response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer);
+            break;
+        case ATT_FIND_INFORMATION_REQUEST:
+            response_len = handle_find_information_request(request_buffer, request_len,response_buffer, response_buffer_size);
+            break;
+        case ATT_FIND_BY_TYPE_VALUE_REQUEST:
+            response_len = handle_find_by_type_value_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_READ_BY_TYPE_REQUEST:  
+            response_len = handle_read_by_type_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_READ_REQUEST:  
+            response_len = handle_read_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_READ_BLOB_REQUEST:  
+            response_len = handle_read_blob_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_READ_MULTIPLE_REQUEST:  
+            response_len = handle_read_multiple_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_READ_BY_GROUP_TYPE_REQUEST:  
+            response_len = handle_read_by_group_type_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_WRITE_REQUEST:
+            response_len = handle_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_PREPARE_WRITE_REQUEST:
+            response_len = handle_prepare_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_EXECUTE_WRITE_REQUEST:
+            response_len = handle_execute_write_request(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_WRITE_COMMAND:
+            handle_write_command(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        case ATT_SIGNED_WRITE_COMAND:
+            handle_signed_write_command(request_buffer, request_len, response_buffer, response_buffer_size);
+            break;
+        default:
+            printf("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]);
+            hexdump2(&request_buffer[9], request_len-9);
+            break;
+    }
+    return response_len;
+}
+
+#if 0
+
+// test profile
+#include "profile.h"
+
+int main(){
+    int acl_buffer_size;
+    uint8_t acl_buffer[27];
+    att_set_db(profile_data);
+    att_dump_attributes();
+
+    uint8_t uuid_1[] = { 0x00, 0x18};
+    acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
+    hexdump2(acl_buffer, acl_buffer_size);
+    
+    uint8_t uuid_3[] = { 0x00, 0x2a};
+    acl_buffer_size = handle_read_by_type_request2(acl_buffer, 19, 0, 0xffff, 2, (uint8_t *) &uuid_3);
+    hexdump2(acl_buffer, acl_buffer_size);
+        
+    acl_buffer_size = handle_find_by_type_value_request2(acl_buffer, 19, 0, 0xffff, 0x2800, 2, (uint8_t *) &uuid_1);
+    hexdump2(acl_buffer, acl_buffer_size);
+
+    uint8_t uuid_4[] = { 0x00, 0x28};
+    acl_buffer_size = handle_read_by_group_type_request2(acl_buffer, 20, 0, 0xffff, 2, (uint8_t *) &uuid_4);
+    hexdump2(acl_buffer, acl_buffer_size);
+    
+    acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 0, 0xffff);
+    hexdump2(acl_buffer, acl_buffer_size);
+    acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 3, 0xffff);
+    hexdump2(acl_buffer, acl_buffer_size);
+    acl_buffer_size = handle_find_information_request2(acl_buffer, 20, 5, 0xffff);
+    hexdump2(acl_buffer, acl_buffer_size);
+
+    acl_buffer_size = handle_read_request2(acl_buffer, 19, 0x0003);
+    hexdump2(acl_buffer, acl_buffer_size);
+
+    return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/att.h	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2011-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+// MARK: Attribute PDU Opcodes 
+#define ATT_ERROR_RESPONSE              0x01
+
+#define ATT_EXCHANGE_MTU_REQUEST        0x02
+#define ATT_EXCHANGE_MTU_RESPONSE       0x03
+
+#define ATT_FIND_INFORMATION_REQUEST    0x04
+#define ATT_FIND_INFORMATION_REPLY      0x05
+#define ATT_FIND_BY_TYPE_VALUE_REQUEST  0x06
+#define ATT_FIND_BY_TYPE_VALUE_RESPONSE 0x07
+
+#define ATT_READ_BY_TYPE_REQUEST        0x08
+#define ATT_READ_BY_TYPE_RESPONSE       0x09
+#define ATT_READ_REQUEST                0x0a
+#define ATT_READ_RESPONSE               0x0b
+#define ATT_READ_BLOB_REQUEST           0x0c
+#define ATT_READ_BLOB_RESPONSE          0x0d
+#define ATT_READ_MULTIPLE_REQUEST       0x0e
+#define ATT_READ_MULTIPLE_RESPONSE      0x0f
+#define ATT_READ_BY_GROUP_TYPE_REQUEST  0x10
+#define ATT_READ_BY_GROUP_TYPE_RESPONSE 0x11
+
+#define ATT_WRITE_REQUEST               0x12
+#define ATT_WRITE_RESPONSE              0x13
+
+#define ATT_PREPARE_WRITE_REQUEST       0x16
+#define ATT_PREPARE_WRITE_RESPONSE      0x17
+#define ATT_EXECUTE_WRITE_REQUEST       0x18
+#define ATT_EXECUTE_WRITE_RESPONSE      0x19
+
+#define ATT_HANDLE_VALUE_NOTIFICATION   0x1b
+#define ATT_HANDLE_VALUE_CONFIRMATION   0x1c
+#define ATT_HANDLE_VALUE_INDICATION     0x1d
+
+
+#define ATT_WRITE_COMMAND               0x52
+#define ATT_SIGNED_WRITE_COMAND         0xD2
+
+// MARK: ATT Error Codes
+#define ATT_ERROR_ATTRIBUTE_INVALID      0x01
+#define ATT_ERROR_INVALID_OFFSET         0x07
+#define ATT_ERROR_ATTRIBUTE_NOT_FOUND    0x0a
+#define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
+
+// MARK: Attribute Property Flags
+#define ATT_PROPERTY_BROADCAST           0x01
+#define ATT_PROPERTY_READ                0x02
+#define ATT_PROPERTY_WRITE_WITHOUT_RESPONSE 0x04
+#define ATT_PROPERTY_WRITE               0x08
+#define ATT_PROPERTY_NOTIFY              0x10
+#define ATT_PROPERTY_INDICATE            0x20
+#define ATT_PROPERTY_AUTHENTICATED_SIGNED_WRITE 0x40
+#define ATT_PROPERTY_EXTENDED_PROPERTIES 0x80
+
+// MARK: Attribute Property Flag, BTstack extension
+// value is asked from client
+#define ATT_PROPERTY_DYNAMIC             0x100
+// 128 bit UUID used
+#define ATT_PROPERTY_UUID128             0x200
+
+// MARK: GATT UUIDs
+#define GATT_PRIMARY_SERVICE_UUID      0x2800
+#define GATT_SECONDARY_SERVICE_UUID    0x2801
+#define GATT_CHARACTERISTICS_UUID      0x2803
+
+#define GAP_SERVICE_UUID          0x1800
+#define GAP_DEVICE_NAME_UUID      0x2a00
+
+#define ATT_TRANSACTION_MODE_NONE      0x0
+#define ATT_TRANSACTION_MODE_ACTIVE    0x1
+#define ATT_TRANSACTION_MODE_EXECUTE   0x2
+#define ATT_TRANSACTION_MODE_CANCEL    0x3
+
+typedef struct att_connection {
+    uint16_t mtu;
+} att_connection_t;
+
+typedef uint8_t signature_t[12];
+
+// 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
+typedef uint16_t (*att_read_callback_t)(uint16_t handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
+
+// ATT Client Write Callback for Dynamic Data
+// @param handle to be written
+// @param transaction - ATT_TRANSACTION_MODE_NONE for regular writes, ATT_TRANSACTION_MODE_ACTIVE for prepared writes and ATT_TRANSACTION_MODE_EXECUTE
+// @param offset into the value - used for queued writes and long attributes
+// @param buffer 
+// @param buffer_size
+// @Param signature used for signed write commmands
+typedef void (*att_write_callback_t)(uint16_t handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size, signature_t * signature);
+
+// MARK: ATT Operations
+
+void att_set_db(uint8_t const * db);
+
+void att_set_read_callback(att_read_callback_t callback);
+
+void att_set_write_callback(att_write_callback_t callback);
+
+void att_dump_attributes(void);
+
+// response buffer size = att_connection->mtu
+uint16_t att_handle_request(att_connection_t * att_connection,
+                            uint8_t * request_buffer,
+                            uint16_t request_len,
+                            uint8_t * response_buffer);
+
+uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
+                                               uint16_t handle,
+                                               uint8_t *value,
+                                               uint16_t value_len, 
+                                               uint8_t * response_buffer);
+
+uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
+                                             uint16_t handle,
+                                             uint8_t *value,
+                                             uint16_t value_len, 
+                                             uint8_t * response_buffer);
+
+    
+    
\ No newline at end of file
--- a/BTstack/btstack/run_loop.h	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/btstack/run_loop.h	Thu Feb 07 14:01:01 2013 +0000
@@ -39,7 +39,7 @@
 
 #include "config.h"
 
-#include <btstack/linked_list.h>
+#include "btstack/linked_list.h"
 
 #include <stdint.h>
 
@@ -50,11 +50,11 @@
 #if defined __cplusplus
 extern "C" {
 #endif
-	
+    
 typedef enum {
-	RUN_LOOP_POSIX = 1,
-	RUN_LOOP_COCOA,
-	RUN_LOOP_EMBEDDED
+    RUN_LOOP_POSIX = 1,
+    RUN_LOOP_COCOA,
+    RUN_LOOP_EMBEDDED
 } RUN_LOOP_TYPE;
 
 typedef struct data_source {
--- a/BTstack/btstack/sdp_util.h	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/btstack/sdp_util.h	Thu Feb 07 14:01:01 2013 +0000
@@ -1,138 +1,138 @@
-/*
- * Copyright (C) 2010 by Matthias Ringwald
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- *  sdp_util.h
- */
-
-#pragma once
-
-#include <stdint.h>
-
-#if defined __cplusplus
-extern "C" {
-#endif
-	
-typedef enum {
-    DE_NIL = 0,
-    DE_UINT,
-    DE_INT,
-    DE_UUID,
-    DE_STRING,
-    DE_BOOL,
-    DE_DES,
-    DE_DEA,
-    DE_URL
-} de_type_t;
-
-typedef enum {
-    DE_SIZE_8 = 0,
-    DE_SIZE_16,
-    DE_SIZE_32,
-    DE_SIZE_64,
-    DE_SIZE_128,
-    DE_SIZE_VAR_8,
-    DE_SIZE_VAR_16,
-    DE_SIZE_VAR_32
-} de_size_t;
-
-// UNIVERSAL ATTRIBUTE DEFINITIONS
-#define SDP_ServiceRecordHandle     0x0000
-#define SDP_ServiceClassIDList      0x0001
-#define SDP_ServiceRecordState      0x0002
-#define SDP_ServiceID               0x0003
-#define SDP_ProtocolDescriptorList  0x0004
-#define SDP_BrowseGroupList		    0x0005
-#define SDP_LanguageBaseAttributeIDList 0x0006
-#define SDP_ServiceInfoTimeToLive	0x0007
-#define SDP_ServiceAvailability		0x0008
-#define SDP_BluetoothProfileDescriptorList 0x0009
-#define SDP_DocumentationURL		0x000a
-#define SDP_ClientExecutableURL     0x000b
-#define SDP_IconURL                 0x000c
-#define SDP_AdditionalProtocolDescriptorList 0x000d
-#define SDP_SupportedFormatsList    0x0303
-
-// SERVICE CLASSES
-#define SDP_OBEXObjectPush    0x1105
-#define SDP_OBEXFileTransfer  0x1106
-#define SDP_PublicBrowseGroup 0x1002
-
-// PROTOCOLS
-#define SDP_SDPProtocol       0x0001
-#define SDP_UDPProtocol       0x0002
-#define SDP_RFCOMMProtocol    0x0003
-#define SDP_OBEXProtocol      0x0008
-#define SDP_L2CAPProtocol     0x0100
-
-// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
-#define SDP_Offest_ServiceName      0x0000
-#define SDP_Offest_ServiceDescription 0x0001
-#define SDP_Offest_ProviderName     0x0002
-
-// OBEX
-#define SDP_vCard_2_1       0x01
-#define SDP_vCard_3_0       0x02
-#define SDP_vCal_1_0        0x03
-#define SDP_iCal_2_0        0x04
-#define SDP_vNote           0x05
-#define SDP_vMessage        0x06
-#define SDP_OBEXFileTypeAny 0xFF
-
-// MARK: DateElement
-void de_dump_data_element(uint8_t * record);
-int de_get_len(uint8_t *header);
-de_size_t de_get_size_type(uint8_t *header);
-de_type_t de_get_element_type(uint8_t *header);
-int de_get_header_size(uint8_t * header);
-void de_create_sequence(uint8_t *header);
-void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
-uint8_t * de_push_sequence(uint8_t *header);
-void de_pop_sequence(uint8_t * parent, uint8_t * child);
-void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
-void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
-
-int de_get_data_size(uint8_t * header);
-void de_add_uuid128(uint8_t * seq, uint8_t * uuid);
-
-// MARK: SDP
-uint16_t  sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
-uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
-uint8_t   sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
-int       sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
-int       spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
-int       sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);  
-
-void      sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
-
-#if defined __cplusplus
-}
-#endif
+/*
+ * Copyright (C) 2010 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  sdp_util.h
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+typedef enum {
+    DE_NIL = 0,
+    DE_UINT,
+    DE_INT,
+    DE_UUID,
+    DE_STRING,
+    DE_BOOL,
+    DE_DES,
+    DE_DEA,
+    DE_URL
+} de_type_t;
+
+typedef enum {
+    DE_SIZE_8 = 0,
+    DE_SIZE_16,
+    DE_SIZE_32,
+    DE_SIZE_64,
+    DE_SIZE_128,
+    DE_SIZE_VAR_8,
+    DE_SIZE_VAR_16,
+    DE_SIZE_VAR_32
+} de_size_t;
+
+// UNIVERSAL ATTRIBUTE DEFINITIONS
+#define SDP_ServiceRecordHandle     0x0000
+#define SDP_ServiceClassIDList      0x0001
+#define SDP_ServiceRecordState      0x0002
+#define SDP_ServiceID               0x0003
+#define SDP_ProtocolDescriptorList  0x0004
+#define SDP_BrowseGroupList         0x0005
+#define SDP_LanguageBaseAttributeIDList 0x0006
+#define SDP_ServiceInfoTimeToLive   0x0007
+#define SDP_ServiceAvailability     0x0008
+#define SDP_BluetoothProfileDescriptorList 0x0009
+#define SDP_DocumentationURL        0x000a
+#define SDP_ClientExecutableURL     0x000b
+#define SDP_IconURL                 0x000c
+#define SDP_AdditionalProtocolDescriptorList 0x000d
+#define SDP_SupportedFormatsList    0x0303
+
+// SERVICE CLASSES
+#define SDP_OBEXObjectPush    0x1105
+#define SDP_OBEXFileTransfer  0x1106
+#define SDP_PublicBrowseGroup 0x1002
+
+// PROTOCOLS
+#define SDP_SDPProtocol       0x0001
+#define SDP_UDPProtocol       0x0002
+#define SDP_RFCOMMProtocol    0x0003
+#define SDP_OBEXProtocol      0x0008
+#define SDP_L2CAPProtocol     0x0100
+
+// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
+#define SDP_Offest_ServiceName      0x0000
+#define SDP_Offest_ServiceDescription 0x0001
+#define SDP_Offest_ProviderName     0x0002
+
+// OBEX
+#define SDP_vCard_2_1       0x01
+#define SDP_vCard_3_0       0x02
+#define SDP_vCal_1_0        0x03
+#define SDP_iCal_2_0        0x04
+#define SDP_vNote           0x05
+#define SDP_vMessage        0x06
+#define SDP_OBEXFileTypeAny 0xFF
+
+// MARK: DateElement
+void de_dump_data_element(uint8_t * record);
+int de_get_len(uint8_t *header);
+de_size_t de_get_size_type(uint8_t *header);
+de_type_t de_get_element_type(uint8_t *header);
+int de_get_header_size(uint8_t * header);
+void de_create_sequence(uint8_t *header);
+void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
+uint8_t * de_push_sequence(uint8_t *header);
+void de_pop_sequence(uint8_t * parent, uint8_t * child);
+void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
+void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
+
+int de_get_data_size(uint8_t * header);
+void de_add_uuid128(uint8_t * seq, uint8_t * uuid);
+
+// MARK: SDP
+uint16_t  sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
+uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
+uint8_t   sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
+int       sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
+int       spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
+int       sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);  
+
+void      sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
+
+#if defined __cplusplus
+}
+#endif
--- a/BTstack/btstack_memory.c	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/btstack_memory.c	Thu Feb 07 14:01:01 2013 +0000
@@ -1,336 +1,336 @@
-/*
- * Copyright (C) 2009-2012 by Matthias Ringwald
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- *    personal benefit and not for any commercial purpose or for
- *    monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at btstack@ringwald.ch
- *
- */
-
-/*
- *  btstsack_memory.h
- *
- *  @brief BTstack memory management via configurable memory pools
- *
- *  @note code semi-atuomatically generated by btstack_memory_generator.py
- *
- */
-
-#include "btstack_memory.h"
-#include <btstack/memory_pool.h>
-
-#include <stdlib.h>
-
-#include "config.h"
-#include "hci.h"
-#include "l2cap.h"
-#include "rfcomm.h"
-
-// MARK: hci_connection_t
-#ifdef MAX_NO_HCI_CONNECTIONS
-#if MAX_NO_HCI_CONNECTIONS > 0
-static hci_connection_t hci_connection_storage[MAX_NO_HCI_CONNECTIONS];
-static memory_pool_t hci_connection_pool;
-void * btstack_memory_hci_connection_get(void){
-    return memory_pool_get(&hci_connection_pool);
-}
-void btstack_memory_hci_connection_free(void *hci_connection){
-    memory_pool_free(&hci_connection_pool, hci_connection);
-}
-#else
-void * btstack_memory_hci_connection_get(void){
-    return NULL;
-}
-void btstack_memory_hci_connection_free(void *hci_connection){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_hci_connection_get(void){
-    return malloc(sizeof(hci_connection_t));
-}
-void  btstack_memory_hci_connection_free(void *hci_connection){
-    free(hci_connection);
-}
-#endif
-
-
-// MARK: l2cap_service_t
-#ifdef MAX_NO_L2CAP_SERVICES
-#if MAX_NO_L2CAP_SERVICES > 0
-static l2cap_service_t l2cap_service_storage[MAX_NO_L2CAP_SERVICES];
-static memory_pool_t l2cap_service_pool;
-void * btstack_memory_l2cap_service_get(void){
-    return memory_pool_get(&l2cap_service_pool);
-}
-void btstack_memory_l2cap_service_free(void *l2cap_service){
-    memory_pool_free(&l2cap_service_pool, l2cap_service);
-}
-#else
-void * btstack_memory_l2cap_service_get(void){
-    return NULL;
-}
-void btstack_memory_l2cap_service_free(void *l2cap_service){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_l2cap_service_get(void){
-    return malloc(sizeof(l2cap_service_t));
-}
-void  btstack_memory_l2cap_service_free(void *l2cap_service){
-    free(l2cap_service);
-}
-#endif
-
-
-// MARK: l2cap_channel_t
-#ifdef MAX_NO_L2CAP_CHANNELS
-#if MAX_NO_L2CAP_CHANNELS > 0
-static l2cap_channel_t l2cap_channel_storage[MAX_NO_L2CAP_CHANNELS];
-static memory_pool_t l2cap_channel_pool;
-void * btstack_memory_l2cap_channel_get(void){
-    return memory_pool_get(&l2cap_channel_pool);
-}
-void btstack_memory_l2cap_channel_free(void *l2cap_channel){
-    memory_pool_free(&l2cap_channel_pool, l2cap_channel);
-}
-#else
-void * btstack_memory_l2cap_channel_get(void){
-    return NULL;
-}
-void btstack_memory_l2cap_channel_free(void *l2cap_channel){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_l2cap_channel_get(void){
-    return malloc(sizeof(l2cap_channel_t));
-}
-void  btstack_memory_l2cap_channel_free(void *l2cap_channel){
-    free(l2cap_channel);
-}
-#endif
-
-
-// MARK: rfcomm_multiplexer_t
-#ifdef MAX_NO_RFCOMM_MULTIPLEXERS
-#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
-static rfcomm_multiplexer_t rfcomm_multiplexer_storage[MAX_NO_RFCOMM_MULTIPLEXERS];
-static memory_pool_t rfcomm_multiplexer_pool;
-void * btstack_memory_rfcomm_multiplexer_get(void){
-    return memory_pool_get(&rfcomm_multiplexer_pool);
-}
-void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
-    memory_pool_free(&rfcomm_multiplexer_pool, rfcomm_multiplexer);
-}
-#else
-void * btstack_memory_rfcomm_multiplexer_get(void){
-    return NULL;
-}
-void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_rfcomm_multiplexer_get(void){
-    return malloc(sizeof(rfcomm_multiplexer_t));
-}
-void  btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
-    free(rfcomm_multiplexer);
-}
-#endif
-
-
-// MARK: rfcomm_service_t
-#ifdef MAX_NO_RFCOMM_SERVICES
-#if MAX_NO_RFCOMM_SERVICES > 0
-static rfcomm_service_t rfcomm_service_storage[MAX_NO_RFCOMM_SERVICES];
-static memory_pool_t rfcomm_service_pool;
-void * btstack_memory_rfcomm_service_get(void){
-    return memory_pool_get(&rfcomm_service_pool);
-}
-void btstack_memory_rfcomm_service_free(void *rfcomm_service){
-    memory_pool_free(&rfcomm_service_pool, rfcomm_service);
-}
-#else
-void * btstack_memory_rfcomm_service_get(void){
-    return NULL;
-}
-void btstack_memory_rfcomm_service_free(void *rfcomm_service){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_rfcomm_service_get(void){
-    return malloc(sizeof(rfcomm_service_t));
-}
-void  btstack_memory_rfcomm_service_free(void *rfcomm_service){
-    free(rfcomm_service);
-}
-#endif
-
-
-// MARK: rfcomm_channel_t
-#ifdef MAX_NO_RFCOMM_CHANNELS
-#if MAX_NO_RFCOMM_CHANNELS > 0
-static rfcomm_channel_t rfcomm_channel_storage[MAX_NO_RFCOMM_CHANNELS];
-static memory_pool_t rfcomm_channel_pool;
-void * btstack_memory_rfcomm_channel_get(void){
-    return memory_pool_get(&rfcomm_channel_pool);
-}
-void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
-    memory_pool_free(&rfcomm_channel_pool, rfcomm_channel);
-}
-#else
-void * btstack_memory_rfcomm_channel_get(void){
-    return NULL;
-}
-void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_rfcomm_channel_get(void){
-    return malloc(sizeof(rfcomm_channel_t));
-}
-void  btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
-    free(rfcomm_channel);
-}
-#endif
-
-
-// MARK: db_mem_device_name_t
-#ifdef MAX_NO_DB_MEM_DEVICE_NAMES
-#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
-static db_mem_device_name_t db_mem_device_name_storage[MAX_NO_DB_MEM_DEVICE_NAMES];
-static memory_pool_t db_mem_device_name_pool;
-void * btstack_memory_db_mem_device_name_get(void){
-    return memory_pool_get(&db_mem_device_name_pool);
-}
-void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
-    memory_pool_free(&db_mem_device_name_pool, db_mem_device_name);
-}
-#else
-void * btstack_memory_db_mem_device_name_get(void){
-    return NULL;
-}
-void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_db_mem_device_name_get(void){
-    return malloc(sizeof(db_mem_device_name_t));
-}
-void  btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
-    free(db_mem_device_name);
-}
-#endif
-
-
-// MARK: db_mem_device_link_key_t
-#ifdef MAX_NO_DB_MEM_DEVICE_LINK_KEYS
-#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
-static db_mem_device_link_key_t db_mem_device_link_key_storage[MAX_NO_DB_MEM_DEVICE_LINK_KEYS];
-static memory_pool_t db_mem_device_link_key_pool;
-void * btstack_memory_db_mem_device_link_key_get(void){
-    return memory_pool_get(&db_mem_device_link_key_pool);
-}
-void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
-    memory_pool_free(&db_mem_device_link_key_pool, db_mem_device_link_key);
-}
-#else
-void * btstack_memory_db_mem_device_link_key_get(void){
-    return NULL;
-}
-void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_db_mem_device_link_key_get(void){
-    return malloc(sizeof(db_mem_device_link_key_t));
-}
-void  btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
-    free(db_mem_device_link_key);
-}
-#endif
-
-
-// MARK: db_mem_service_t
-#ifdef MAX_NO_DB_MEM_SERVICES
-#if MAX_NO_DB_MEM_SERVICES > 0
-static db_mem_service_t db_mem_service_storage[MAX_NO_DB_MEM_SERVICES];
-static memory_pool_t db_mem_service_pool;
-void * btstack_memory_db_mem_service_get(void){
-    return memory_pool_get(&db_mem_service_pool);
-}
-void btstack_memory_db_mem_service_free(void *db_mem_service){
-    memory_pool_free(&db_mem_service_pool, db_mem_service);
-}
-#else
-void * btstack_memory_db_mem_service_get(void){
-    return NULL;
-}
-void btstack_memory_db_mem_service_free(void *db_mem_service){
-};
-#endif
-#elif defined(HAVE_MALLOC)
-void * btstack_memory_db_mem_service_get(void){
-    return malloc(sizeof(db_mem_service_t));
-}
-void  btstack_memory_db_mem_service_free(void *db_mem_service){
-    free(db_mem_service);
-}
-#endif
-
-// init
-void btstack_memory_init(void){
-#if MAX_NO_HCI_CONNECTIONS > 0
-    memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NO_HCI_CONNECTIONS, sizeof(hci_connection_t));
-#endif
-#if MAX_NO_L2CAP_SERVICES > 0
-    memory_pool_create(&l2cap_service_pool, l2cap_service_storage, MAX_NO_L2CAP_SERVICES, sizeof(l2cap_service_t));
-#endif
-#if MAX_NO_L2CAP_CHANNELS > 0
-    memory_pool_create(&l2cap_channel_pool, l2cap_channel_storage, MAX_NO_L2CAP_CHANNELS, sizeof(l2cap_channel_t));
-#endif
-#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
-    memory_pool_create(&rfcomm_multiplexer_pool, rfcomm_multiplexer_storage, MAX_NO_RFCOMM_MULTIPLEXERS, sizeof(rfcomm_multiplexer_t));
-#endif
-#if MAX_NO_RFCOMM_SERVICES > 0
-    memory_pool_create(&rfcomm_service_pool, rfcomm_service_storage, MAX_NO_RFCOMM_SERVICES, sizeof(rfcomm_service_t));
-#endif
-#if MAX_NO_RFCOMM_CHANNELS > 0
-    memory_pool_create(&rfcomm_channel_pool, rfcomm_channel_storage, MAX_NO_RFCOMM_CHANNELS, sizeof(rfcomm_channel_t));
-#endif
-#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
-    memory_pool_create(&db_mem_device_name_pool, db_mem_device_name_storage, MAX_NO_DB_MEM_DEVICE_NAMES, sizeof(db_mem_device_name_t));
-#endif
-#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
-    memory_pool_create(&db_mem_device_link_key_pool, db_mem_device_link_key_storage, MAX_NO_DB_MEM_DEVICE_LINK_KEYS, sizeof(db_mem_device_link_key_t));
-#endif
-#if MAX_NO_DB_MEM_SERVICES > 0
-    memory_pool_create(&db_mem_service_pool, db_mem_service_storage, MAX_NO_DB_MEM_SERVICES, sizeof(db_mem_service_t));
-#endif
-}
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  btstsack_memory.h
+ *
+ *  @brief BTstack memory management via configurable memory pools
+ *
+ *  @note code semi-atuomatically generated by btstack_memory_generator.py
+ *
+ */
+
+#include "btstack_memory.h"
+#include "btstack/memory_pool.h"
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "hci.h"
+#include "l2cap.h"
+#include "rfcomm.h"
+
+// MARK: hci_connection_t
+#ifdef MAX_NO_HCI_CONNECTIONS
+#if MAX_NO_HCI_CONNECTIONS > 0
+static hci_connection_t hci_connection_storage[MAX_NO_HCI_CONNECTIONS];
+static memory_pool_t hci_connection_pool;
+void * btstack_memory_hci_connection_get(void){
+    return memory_pool_get(&hci_connection_pool);
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+    memory_pool_free(&hci_connection_pool, hci_connection);
+}
+#else
+void * btstack_memory_hci_connection_get(void){
+    return NULL;
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_hci_connection_get(void){
+    return malloc(sizeof(hci_connection_t));
+}
+void  btstack_memory_hci_connection_free(void *hci_connection){
+    free(hci_connection);
+}
+#endif
+
+
+// MARK: l2cap_service_t
+#ifdef MAX_NO_L2CAP_SERVICES
+#if MAX_NO_L2CAP_SERVICES > 0
+static l2cap_service_t l2cap_service_storage[MAX_NO_L2CAP_SERVICES];
+static memory_pool_t l2cap_service_pool;
+void * btstack_memory_l2cap_service_get(void){
+    return memory_pool_get(&l2cap_service_pool);
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+    memory_pool_free(&l2cap_service_pool, l2cap_service);
+}
+#else
+void * btstack_memory_l2cap_service_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_service_get(void){
+    return malloc(sizeof(l2cap_service_t));
+}
+void  btstack_memory_l2cap_service_free(void *l2cap_service){
+    free(l2cap_service);
+}
+#endif
+
+
+// MARK: l2cap_channel_t
+#ifdef MAX_NO_L2CAP_CHANNELS
+#if MAX_NO_L2CAP_CHANNELS > 0
+static l2cap_channel_t l2cap_channel_storage[MAX_NO_L2CAP_CHANNELS];
+static memory_pool_t l2cap_channel_pool;
+void * btstack_memory_l2cap_channel_get(void){
+    return memory_pool_get(&l2cap_channel_pool);
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    memory_pool_free(&l2cap_channel_pool, l2cap_channel);
+}
+#else
+void * btstack_memory_l2cap_channel_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_channel_get(void){
+    return malloc(sizeof(l2cap_channel_t));
+}
+void  btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    free(l2cap_channel);
+}
+#endif
+
+
+// MARK: rfcomm_multiplexer_t
+#ifdef MAX_NO_RFCOMM_MULTIPLEXERS
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+static rfcomm_multiplexer_t rfcomm_multiplexer_storage[MAX_NO_RFCOMM_MULTIPLEXERS];
+static memory_pool_t rfcomm_multiplexer_pool;
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return memory_pool_get(&rfcomm_multiplexer_pool);
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    memory_pool_free(&rfcomm_multiplexer_pool, rfcomm_multiplexer);
+}
+#else
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return malloc(sizeof(rfcomm_multiplexer_t));
+}
+void  btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    free(rfcomm_multiplexer);
+}
+#endif
+
+
+// MARK: rfcomm_service_t
+#ifdef MAX_NO_RFCOMM_SERVICES
+#if MAX_NO_RFCOMM_SERVICES > 0
+static rfcomm_service_t rfcomm_service_storage[MAX_NO_RFCOMM_SERVICES];
+static memory_pool_t rfcomm_service_pool;
+void * btstack_memory_rfcomm_service_get(void){
+    return memory_pool_get(&rfcomm_service_pool);
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    memory_pool_free(&rfcomm_service_pool, rfcomm_service);
+}
+#else
+void * btstack_memory_rfcomm_service_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_service_get(void){
+    return malloc(sizeof(rfcomm_service_t));
+}
+void  btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    free(rfcomm_service);
+}
+#endif
+
+
+// MARK: rfcomm_channel_t
+#ifdef MAX_NO_RFCOMM_CHANNELS
+#if MAX_NO_RFCOMM_CHANNELS > 0
+static rfcomm_channel_t rfcomm_channel_storage[MAX_NO_RFCOMM_CHANNELS];
+static memory_pool_t rfcomm_channel_pool;
+void * btstack_memory_rfcomm_channel_get(void){
+    return memory_pool_get(&rfcomm_channel_pool);
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    memory_pool_free(&rfcomm_channel_pool, rfcomm_channel);
+}
+#else
+void * btstack_memory_rfcomm_channel_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_channel_get(void){
+    return malloc(sizeof(rfcomm_channel_t));
+}
+void  btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    free(rfcomm_channel);
+}
+#endif
+
+
+// MARK: db_mem_device_name_t
+#ifdef MAX_NO_DB_MEM_DEVICE_NAMES
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+static db_mem_device_name_t db_mem_device_name_storage[MAX_NO_DB_MEM_DEVICE_NAMES];
+static memory_pool_t db_mem_device_name_pool;
+void * btstack_memory_db_mem_device_name_get(void){
+    return memory_pool_get(&db_mem_device_name_pool);
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    memory_pool_free(&db_mem_device_name_pool, db_mem_device_name);
+}
+#else
+void * btstack_memory_db_mem_device_name_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_name_get(void){
+    return malloc(sizeof(db_mem_device_name_t));
+}
+void  btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    free(db_mem_device_name);
+}
+#endif
+
+
+// MARK: db_mem_device_link_key_t
+#ifdef MAX_NO_DB_MEM_DEVICE_LINK_KEYS
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+static db_mem_device_link_key_t db_mem_device_link_key_storage[MAX_NO_DB_MEM_DEVICE_LINK_KEYS];
+static memory_pool_t db_mem_device_link_key_pool;
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return memory_pool_get(&db_mem_device_link_key_pool);
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    memory_pool_free(&db_mem_device_link_key_pool, db_mem_device_link_key);
+}
+#else
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return malloc(sizeof(db_mem_device_link_key_t));
+}
+void  btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    free(db_mem_device_link_key);
+}
+#endif
+
+
+// MARK: db_mem_service_t
+#ifdef MAX_NO_DB_MEM_SERVICES
+#if MAX_NO_DB_MEM_SERVICES > 0
+static db_mem_service_t db_mem_service_storage[MAX_NO_DB_MEM_SERVICES];
+static memory_pool_t db_mem_service_pool;
+void * btstack_memory_db_mem_service_get(void){
+    return memory_pool_get(&db_mem_service_pool);
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+    memory_pool_free(&db_mem_service_pool, db_mem_service);
+}
+#else
+void * btstack_memory_db_mem_service_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_service_get(void){
+    return malloc(sizeof(db_mem_service_t));
+}
+void  btstack_memory_db_mem_service_free(void *db_mem_service){
+    free(db_mem_service);
+}
+#endif
+
+// init
+void btstack_memory_init(void){
+#if MAX_NO_HCI_CONNECTIONS > 0
+    memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NO_HCI_CONNECTIONS, sizeof(hci_connection_t));
+#endif
+#if MAX_NO_L2CAP_SERVICES > 0
+    memory_pool_create(&l2cap_service_pool, l2cap_service_storage, MAX_NO_L2CAP_SERVICES, sizeof(l2cap_service_t));
+#endif
+#if MAX_NO_L2CAP_CHANNELS > 0
+    memory_pool_create(&l2cap_channel_pool, l2cap_channel_storage, MAX_NO_L2CAP_CHANNELS, sizeof(l2cap_channel_t));
+#endif
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+    memory_pool_create(&rfcomm_multiplexer_pool, rfcomm_multiplexer_storage, MAX_NO_RFCOMM_MULTIPLEXERS, sizeof(rfcomm_multiplexer_t));
+#endif
+#if MAX_NO_RFCOMM_SERVICES > 0
+    memory_pool_create(&rfcomm_service_pool, rfcomm_service_storage, MAX_NO_RFCOMM_SERVICES, sizeof(rfcomm_service_t));
+#endif
+#if MAX_NO_RFCOMM_CHANNELS > 0
+    memory_pool_create(&rfcomm_channel_pool, rfcomm_channel_storage, MAX_NO_RFCOMM_CHANNELS, sizeof(rfcomm_channel_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+    memory_pool_create(&db_mem_device_name_pool, db_mem_device_name_storage, MAX_NO_DB_MEM_DEVICE_NAMES, sizeof(db_mem_device_name_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+    memory_pool_create(&db_mem_device_link_key_pool, db_mem_device_link_key_storage, MAX_NO_DB_MEM_DEVICE_LINK_KEYS, sizeof(db_mem_device_link_key_t));
+#endif
+#if MAX_NO_DB_MEM_SERVICES > 0
+    memory_pool_create(&db_mem_service_pool, db_mem_service_storage, MAX_NO_DB_MEM_SERVICES, sizeof(db_mem_service_t));
+#endif
+}
--- a/BTstack/config.h	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/config.h	Thu Feb 07 14:01:01 2013 +0000
@@ -1,24 +1,29 @@
+// Replaced by LE version
+
 #define EMBEDDED
-#define HAVE_TICK
+
+#define ENABLE_LOG_DEBUG
+#define ENABLE_LOG_INFO
+#define ENABLE_LOG_ERROR
 
 //#define HAVE_INIT_SCRIPT
-//#define HAVE_BZERO
-//#define HAVE_EHCILL
+#define HAVE_TICK
 
-#define ENABLE_LOG_INFO 
-#define ENABLE_LOG_ERROR
+//#define HAVE_EHCILL
+#define HAVE_BLE
+
+#define ASYNC_BUFFERS 1
+
 
 #define HCI_ACL_PAYLOAD_SIZE 52
 
-#define HAVE_MALLOC
-
-//#define MAX_SPP_CONNECTIONS 1
-//#define MAX_NO_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
-//#define MAX_NO_L2CAP_SERVICES  2
-//#define MAX_NO_L2CAP_CHANNELS  (1+MAX_SPP_CONNECTIONS)
-//#define MAX_NO_RFCOMM_MULTIPLEXERS MAX_SPP_CONNECTIONS
-//#define MAX_NO_RFCOMM_SERVICES 1
-//#define MAX_NO_RFCOMM_CHANNELS MAX_SPP_CONNECTIONS
-//#define MAX_NO_DB_MEM_DEVICE_LINK_KEYS  2
-//#define MAX_NO_DB_MEM_DEVICE_NAMES 0
-//#define MAX_NO_DB_MEM_SERVICES 1
+// 
+#define MAX_NO_HCI_CONNECTIONS 1
+#define MAX_NO_L2CAP_SERVICES  0
+#define MAX_NO_L2CAP_CHANNELS  0
+#define MAX_NO_RFCOMM_MULTIPLEXERS 0
+#define MAX_NO_RFCOMM_SERVICES 0
+#define MAX_NO_RFCOMM_CHANNELS 0
+#define MAX_NO_DB_MEM_DEVICE_LINK_KEYS  2
+#define MAX_NO_DB_MEM_DEVICE_NAMES 0
+#define MAX_NO_DB_MEM_SERVICES 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/global.h	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,10 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+
+extern uint8_t  startup_state;
+extern uint8_t  connection_status;
+extern unsigned led1_on_count;
+extern uint8_t  led1_on_state;
+extern unsigned timer_counter;
+
+#endif
--- a/BTstack/hci.c	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/hci.c	Thu Feb 07 14:01:01 2013 +0000
@@ -58,7 +58,7 @@
 #include "debug.h"
 #include "hci_dump.h"
 
-#include <btstack/hci_cmds.h>
+#include "btstack/hci_cmds.h"
 
 #define HCI_CONNECTION_TIMEOUT_MS 10000
 
@@ -677,9 +677,9 @@
     }
     
     hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
-	
-	// execute main loop
-	hci_run();
+    
+    // execute main loop
+    hci_run();
 }
 
 void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
@@ -983,11 +983,11 @@
     }
 
     // create internal event
-	hci_emit_state();
+    hci_emit_state();
     
-	// trigger next/first action
-	hci_run();
-	
+    // trigger next/first action
+    hci_run();
+    
     return 0;
 }
 
@@ -1109,18 +1109,18 @@
                         log_info("hci_run: init script done\n\r");
                     }
                     // otherwise continue
-					hci_send_cmd(&hci_read_bd_addr);
-					break;
-				case 4:
-					hci_send_cmd(&hci_read_buffer_size);
-					break;
+                    hci_send_cmd(&hci_read_bd_addr);
+                    break;
+                case 4:
+                    hci_send_cmd(&hci_read_buffer_size);
+                    break;
                 case 5:
                     // ca. 15 sec
                     hci_send_cmd(&hci_write_page_timeout, 0x6000);
                     break;
-				case 6:
-					hci_send_cmd(&hci_write_scan_enable, (hci_stack.connectable << 1) | hci_stack.discoverable); // page scan
-					break;
+                case 6:
+                    hci_send_cmd(&hci_write_scan_enable, (hci_stack.connectable << 1) | hci_stack.discoverable); // page scan
+                    break;
                 case 7:
 #ifndef EMBEDDED
                 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/memory_pool.c	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  memory_pool.c
+ *
+ *  Fixed-size block allocation
+ *
+ *  Free blocks are kept in singly linked list
+ *
+ */
+
+#include "btstack/memory_pool.h"
+#include <stddef.h>
+
+typedef struct node {
+    struct node * next;
+} node_t;
+
+void memory_pool_create(memory_pool_t *pool, void * storage, int count, int block_size){
+    node_t *free_blocks = (node_t*) pool;
+    char   *mem_ptr = (char *) storage;
+    int i;
+    
+    // create singly linked list of all available blocks
+    free_blocks->next = NULL;
+    for (i = 0 ; i < count ; i++){
+        memory_pool_free(pool, mem_ptr);
+        mem_ptr += block_size;
+    }
+}
+
+void * memory_pool_get(memory_pool_t *pool){
+    node_t *free_blocks = (node_t*) pool;
+    
+    if (!free_blocks->next) return NULL;
+    
+    // remove first
+    node_t *node      = free_blocks->next;
+    free_blocks->next = node->next;
+    
+    return (void*) node;
+}
+
+void memory_pool_free(memory_pool_t *pool, void * block){
+    node_t *free_blocks = (node_t*) pool;
+    node_t *node        = (node_t*) block;
+    // add block as node to list
+    node->next          = free_blocks->next;
+    free_blocks->next   = node;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/profile.h	Thu Feb 07 14:01:01 2013 +0000
@@ -0,0 +1,42 @@
+// profile.h generated from profile.gatt for BTstack
+
+// binary representation
+// attribute size in bytes (16), flags(16), handle (16), uuid (16/128), value(...)
+
+#include <stdint.h>
+
+const uint8_t profile_data[] =
+{
+    // 0x0001 PRIMARY_SERVICE-GAP_SERVICE
+    0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18, 
+    // 0x0002 CHARACTERISTIC-GAP_DEVICE_NAME-READ
+    0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a, 
+    // 0x0003 VALUE-GAP_DEVICE_NAME-READ-"mbed BLE TEST"
+    0x15, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x2a, 0x6d, 0x62, 0x65, 0x64, 0x20, 0x42, 0x4c, 0x45, 0x20, 0x54, 0x45, 0x53, 0x54, 
+    // 0x0004 CHARACTERISTIC-GAP_APPEARANCE-READ
+    0x0d, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x28, 0x02, 0x05, 0x00, 0x01, 0x2a, 
+    // 0x0005 VALUE-GAP_APPEARANCE-READ-00 00
+    0x0a, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x2a, 0x00, 0x00, 
+    // 0x0006 PRIMARY_SERVICE-GATT_SERVICE
+    0x0a, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x28, 0x01, 0x18, 
+    // 0x0007 CHARACTERISTIC-GATT_SERVICE_CHANGED-READ
+    0x0d, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x02, 0x08, 0x00, 0x05, 0x2a, 
+    // 0x0008 VALUE-GATT_SERVICE_CHANGED-READ-
+    0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x05, 0x2a, 
+    // 0x0009 PRIMARY_SERVICE-FFF0
+    0x0a, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x28, 0xf0, 0xff, 
+    // 0x000a CHARACTERISTIC-FFF1-READ | WRITE | DYNAMIC
+    0x0d, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x28, 0x0a, 0x0b, 0x00, 0xf1, 0xff, 
+    // 0x000b VALUE-FFF1-READ | WRITE | DYNAMIC-
+    0x08, 0x00, 0x0a, 0x01, 0x0b, 0x00, 0xf1, 0xff, 
+    // 0x000c CHARACTERISTIC-FFF2-READ | WRITE | DYNAMIC
+    0x0d, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x03, 0x28, 0x0a, 0x0d, 0x00, 0xf2, 0xff, 
+    // 0x000d VALUE-FFF2-READ | WRITE | DYNAMIC-
+    0x08, 0x00, 0x0a, 0x01, 0x0d, 0x00, 0xf2, 0xff, 
+    // 0x000e CHARACTERISTIC-00001234-0000-1000-8000-00805F9B34FB-READ | WRITE | DYNAMIC
+    0x1b, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x03, 0x28, 0x0a, 0x0f, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x34, 0x12, 0x00, 0x00, 
+    // 0x000f VALUE-00001234-0000-1000-8000-00805F9B34FB-READ | WRITE | DYNAMIC-
+    0x16, 0x00, 0x0a, 0x03, 0x0f, 0x00, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x34, 0x12, 0x00, 0x00, 
+    // END
+    0x00, 0x00, 
+}; // total size 124 bytes 
--- a/BTstack/rfcomm.c	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1869 +0,0 @@
-/*
- * Copyright (C) 2009-2012 by Matthias Ringwald
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- *    personal benefit and not for any commercial purpose or for
- *    monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at btstack@ringwald.ch
- *
- */
-
-/*
- *  rfcomm.c
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // memcpy
-#include <stdint.h>
-
-#include <btstack/btstack.h>
-#include <btstack/hci_cmds.h>
-#include <btstack/utils.h>
-
-#include <btstack/utils.h>
-#include "btstack_memory.h"
-#include "hci.h"
-#include "hci_dump.h"
-#include "debug.h"
-#include "rfcomm.h"
-
-// workaround for missing PRIxPTR on mspgcc (16/20-bit MCU)
-#ifndef PRIxPTR
-#if defined(__MSP430X__)  &&  defined(__MSP430X_LARGE__)
-#define PRIxPTR "lx"
-#else
-#define PRIxPTR "x"
-#endif
-#endif
-
-
-// Control field values      bit no.       1 2 3 4 PF 6 7 8
-#define BT_RFCOMM_SABM       0x3F       // 1 1 1 1  1 1 0 0
-#define BT_RFCOMM_UA         0x73       // 1 1 0 0  1 1 1 0
-#define BT_RFCOMM_DM         0x0F       // 1 1 1 1  0 0 0 0
-#define BT_RFCOMM_DM_PF      0x1F        // 1 1 1 1  1 0 0 0
-#define BT_RFCOMM_DISC       0x53       // 1 1 0 0  1 0 1 0
-#define BT_RFCOMM_UIH        0xEF       // 1 1 1 1  0 1 1 1
-#define BT_RFCOMM_UIH_PF     0xFF       // 1 1 1 1  0 1 1 1
-
-// Multiplexer message types 
-#define BT_RFCOMM_CLD_CMD    0xC3
-#define BT_RFCOMM_FCON_CMD   0xA3
-#define BT_RFCOMM_FCON_RSP   0xA1
-#define BT_RFCOMM_FCOFF_CMD  0x63
-#define BT_RFCOMM_FCOFF_RSP  0x61
-#define BT_RFCOMM_MSC_CMD    0xE3
-#define BT_RFCOMM_MSC_RSP    0xE1
-#define BT_RFCOMM_NSC_RSP    0x11
-#define BT_RFCOMM_PN_CMD     0x83
-#define BT_RFCOMM_PN_RSP     0x81
-#define BT_RFCOMM_RLS_CMD    0x53
-#define BT_RFCOMM_RLS_RSP    0x51
-#define BT_RFCOMM_RPN_CMD    0x93
-#define BT_RFCOMM_RPN_RSP    0x91
-#define BT_RFCOMM_TEST_CMD   0x23
-#define BT_RFCOMM_TEST_RSP   0x21
-
-#define RFCOMM_MULIPLEXER_TIMEOUT_MS 60000
-
-// FCS calc 
-#define BT_RFCOMM_CODE_WORD         0xE0 // pol = x8+x2+x1+1
-#define BT_RFCOMM_CRC_CHECK_LEN     3
-#define BT_RFCOMM_UIHCRC_CHECK_LEN  2
-
-#include "l2cap.h"
-
-// used for debugging
-// #define RFCOMM_LOG_CREDITS
-
-// global rfcomm data
-static uint16_t      rfcomm_client_cid_generator;  // used for client channel IDs
-
-// linked lists for all
-static linked_list_t rfcomm_multiplexers = NULL;
-static linked_list_t rfcomm_channels = NULL;
-static linked_list_t rfcomm_services = NULL;
-
-static void (*app_packet_handler)(void * connection, uint8_t packet_type,
-                                  uint16_t channel, uint8_t *packet, uint16_t size);
-
-static void rfcomm_run(void);
-static void rfcomm_hand_out_credits(void);
-static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event);
-static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event);
-static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel);
-static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event);
-
-
-// MARK: RFCOMM CLIENT EVENTS
-
-// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
-static void rfcomm_emit_connection_request(rfcomm_channel_t *channel) {
-    uint8_t event[11];
-    event[0] = RFCOMM_EVENT_INCOMING_CONNECTION;
-    event[1] = sizeof(event) - 2;
-    bt_flip_addr(&event[2], channel->multiplexer->remote_addr);
-    event[8] = channel->dlci >> 1;
-    bt_store_16(event, 9, channel->rfcomm_cid);
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
-}
-
-// API Change: BTstack-0.3.50x uses
-// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
-// next Cydia release will use SVN version of this
-// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
-static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status) {
-    uint8_t event[16];
-    uint8_t pos = 0;
-    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
-    event[pos++] = sizeof(event) - 2;
-    event[pos++] = status;
-    bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
-    bt_store_16(event,  pos, channel->multiplexer->con_handle);   pos += 2;
-    event[pos++] = channel->dlci >> 1;
-    bt_store_16(event, pos, channel->rfcomm_cid); pos += 2;       // channel ID
-    bt_store_16(event, pos, channel->max_frame_size); pos += 2;   // max frame size
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
-}
-
-static void rfcomm_emit_channel_open_failed_outgoing_memory(void * connection, bd_addr_t *addr, uint8_t server_channel){
-    uint8_t event[16];
-    uint8_t pos = 0;
-    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
-    event[pos++] = sizeof(event) - 2;
-    event[pos++] = BTSTACK_MEMORY_ALLOC_FAILED;
-    bt_flip_addr(&event[pos], *addr); pos += 6;
-    bt_store_16(event,  pos, 0);   pos += 2;
-    event[pos++] = server_channel;
-    bt_store_16(event, pos, 0); pos += 2;   // channel ID
-    bt_store_16(event, pos, 0); pos += 2;   // max frame size
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
-}
-
-// data: event(8), len(8), creidts incoming(8), new credits incoming(8), credits outgoing(8)
-static inline void rfcomm_emit_credit_status(rfcomm_channel_t * channel) {
-#ifdef RFCOMM_LOG_CREDITS
-    uint8_t event[5];
-    event[0] = 0x88;
-    event[1] = sizeof(event) - 2;
-    event[2] = channel->credits_incoming;
-    event[3] = channel->new_credits_incoming;
-    event[4] = channel->credits_outgoing;
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-#endif
-}
-
-// data: event(8), len(8), rfcomm_cid(16)
-static void rfcomm_emit_channel_closed(rfcomm_channel_t * channel) {
-    uint8_t event[4];
-    event[0] = RFCOMM_EVENT_CHANNEL_CLOSED;
-    event[1] = sizeof(event) - 2;
-    bt_store_16(event, 2, channel->rfcomm_cid);
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
-}
-
-static void rfcomm_emit_credits(rfcomm_channel_t * channel, uint8_t credits) {
-    uint8_t event[5];
-    event[0] = RFCOMM_EVENT_CREDITS;
-    event[1] = sizeof(event) - 2;
-    bt_store_16(event, 2, channel->rfcomm_cid);
-    event[4] = credits;
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
-}
-
-static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
-    uint8_t event[4];
-    event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
-    event[1] = sizeof(event) - 2;
-    event[2] = status;
-    event[3] = channel;
-    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
-    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
-}
-
-// MARK: RFCOMM MULTIPLEXER HELPER
-
-static uint16_t rfcomm_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
-
-    // Assume RFCOMM header with credits and single byte length field
-    uint16_t max_frame_size = l2cap_mtu - 5;
-    
-    // single byte can denote len up to 127
-    if (max_frame_size > 127) {
-        max_frame_size--;
-    }
-
-    log_info("rfcomm_max_frame_size_for_l2cap_mtu:  %u -> %u\n", l2cap_mtu, max_frame_size);
-    return max_frame_size;
-}
-
-static void rfcomm_multiplexer_initialize(rfcomm_multiplexer_t *multiplexer){
-
-    memset(multiplexer, 0, sizeof(rfcomm_multiplexer_t));
-
-    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
-    multiplexer->l2cap_credits = 0;
-    multiplexer->send_dm_for_dlci = 0;
-    multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
-}
-
-static rfcomm_multiplexer_t * rfcomm_multiplexer_create_for_addr(bd_addr_t *addr){
-    
-    // alloc structure 
-    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t*)btstack_memory_rfcomm_multiplexer_get();
-    if (!multiplexer) return NULL;
-    
-    // fill in 
-    rfcomm_multiplexer_initialize(multiplexer);
-    BD_ADDR_COPY(&multiplexer->remote_addr, addr);
-
-    // add to services list
-    linked_list_add(&rfcomm_multiplexers, (linked_item_t *) multiplexer);
-    
-    return multiplexer;
-}
-
-static rfcomm_multiplexer_t * rfcomm_multiplexer_for_addr(bd_addr_t *addr){
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
-        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
-        if (BD_ADDR_CMP(addr, multiplexer->remote_addr) == 0) {
-            return multiplexer;
-        };
-    }
-    return NULL;
-}
-
-static rfcomm_multiplexer_t * rfcomm_multiplexer_for_l2cap_cid(uint16_t l2cap_cid) {
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
-        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
-        if (multiplexer->l2cap_cid == l2cap_cid) {
-            return multiplexer;
-        };
-    }
-    return NULL;
-}
-
-static int rfcomm_multiplexer_has_channels(rfcomm_multiplexer_t * multiplexer){
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
-        if (channel->multiplexer == multiplexer) {
-            return 1;
-        }
-    }
-    return 0;
-}
-
-// MARK: RFCOMM CHANNEL HELPER
-
-static void rfcomm_dump_channels(void){
-#ifndef EMBEDDED
-    linked_item_t * it;
-    int channels = 0;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
-        log_info("Channel #%u: addr %p, state %u\n", channels, channel, channel->state);
-        channels++;
-    }
-#endif
-}
-
-static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer, 
-                               rfcomm_service_t *service, uint8_t server_channel){
-    
-    // don't use 0 as channel id
-    if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
-    
-    // setup channel
-    memset(channel, 0, sizeof(rfcomm_channel_t));
-    
-    channel->state             = RFCOMM_CHANNEL_CLOSED;
-    channel->state_var         = RFCOMM_CHANNEL_STATE_VAR_NONE;
-    
-    channel->multiplexer      = multiplexer;
-    channel->service          = service;
-    channel->rfcomm_cid       = rfcomm_client_cid_generator++;
-    channel->max_frame_size   = multiplexer->max_frame_size;
-
-    channel->credits_incoming = 0;
-    channel->credits_outgoing = 0;
-    channel->packets_granted  = 0;
-
-    // incoming flow control not active
-    channel->new_credits_incoming  = 0x30;
-    channel->incoming_flow_control = 0;
-    
-    if (service) {
-        // incoming connection
-        channel->outgoing = 0;
-        channel->dlci = (server_channel << 1) |  multiplexer->outgoing;
-        if (channel->max_frame_size > service->max_frame_size) {
-            channel->max_frame_size = service->max_frame_size;
-        }
-        channel->incoming_flow_control = service->incoming_flow_control;
-        channel->new_credits_incoming  = service->incoming_initial_credits;
-    } else {
-        // outgoing connection
-        channel->outgoing = 1;
-        channel->dlci = (server_channel << 1) | (multiplexer->outgoing ^ 1);
-    }
-}
-
-// service == NULL -> outgoing channel
-static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
-                                                rfcomm_service_t * service, uint8_t server_channel){
-
-    log_info("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
-    rfcomm_dump_channels();
-
-    // alloc structure 
-    rfcomm_channel_t * channel = (rfcomm_channel_t*)btstack_memory_rfcomm_channel_get();
-    if (!channel) return NULL;
-    
-    // fill in 
-    rfcomm_channel_initialize(channel, multiplexer, service, server_channel);
-    
-    // add to services list
-    linked_list_add(&rfcomm_channels, (linked_item_t *) channel);
-    
-    return channel;
-}
-
-static rfcomm_channel_t * rfcomm_channel_for_rfcomm_cid(uint16_t rfcomm_cid){
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
-        if (channel->rfcomm_cid == rfcomm_cid) {
-            return channel;
-        };
-    }
-    return NULL;
-}
-
-static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multiplexer_t * multiplexer, uint8_t dlci){
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
-        if (channel->dlci == dlci && channel->multiplexer == multiplexer) {
-            return channel;
-        };
-    }
-    return NULL;
-}
-
-static rfcomm_service_t * rfcomm_service_for_channel(uint8_t server_channel){
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
-        rfcomm_service_t * service = ((rfcomm_service_t *) it);
-        if ( service->server_channel == server_channel){
-            return service;
-        };
-    }
-    return NULL;
-}
-
-// MARK: RFCOMM SEND
-
-/**
- * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
- */
-static int rfcomm_send_packet_for_multiplexer(rfcomm_multiplexer_t *multiplexer, uint8_t address, uint8_t control, uint8_t credits, uint8_t *data, uint16_t len){
-
-    if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) return BTSTACK_ACL_BUFFERS_FULL;
-    
-    uint8_t * rfcomm_out_buffer = l2cap_get_outgoing_buffer();
-    
-    uint16_t pos = 0;
-    uint8_t crc_fields = 3;
-    
-    rfcomm_out_buffer[pos++] = address;
-    rfcomm_out_buffer[pos++] = control;
-    
-    // length field can be 1 or 2 octets
-    if (len < 128){
-        rfcomm_out_buffer[pos++] = (len << 1)| 1;     // bits 0-6
-    } else {
-        rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
-        rfcomm_out_buffer[pos++] = len >> 7;          // bits 7-14
-        crc_fields++;
-    }
-
-    // add credits for UIH frames when PF bit is set
-    if (control == BT_RFCOMM_UIH_PF){
-        rfcomm_out_buffer[pos++] = credits;
-    }
-    
-    // copy actual data
-    if (len) {
-        memcpy(&rfcomm_out_buffer[pos], data, len);
-        pos += len;
-    }
-    
-    // UIH frames only calc FCS over address + control (5.1.1)
-    if ((control & 0xef) == BT_RFCOMM_UIH){
-        crc_fields = 2;
-    }
-    rfcomm_out_buffer[pos++] =  crc8_calc(rfcomm_out_buffer, crc_fields); // calc fcs
-
-    int credits_taken = 0;
-    if (multiplexer->l2cap_credits){
-        credits_taken++;
-        multiplexer->l2cap_credits--;
-    } else {
-        log_info( "rfcomm_send_packet addr %02x, ctrl %02x size %u without l2cap credits\n", address, control, pos);
-    }
-    
-    int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
-    
-    if (err) {
-        // undo credit counting
-        multiplexer->l2cap_credits += credits_taken;
-    }
-    return err;
-}
-
-// C/R Flag in Address
-// - terms: initiator = station that creates multiplexer with SABM
-// - terms: responder = station that responds to multiplexer setup with UA
-// "For SABM, UA, DM and DISC frames C/R bit is set according to Table 1 in GSM 07.10, section 5.2.1.2"
-//    - command initiator = 1 /response responder = 1
-//    - command responder = 0 /response initiator = 0
-// "For UIH frames, the C/R bit is always set according to section 5.4.3.1 in GSM 07.10. 
-//  This applies independently of what is contained wthin the UIH frames, either data or control messages."
-//    - c/r = 1 for frames by initiating station, 0 = for frames by responding station
-
-// C/R Flag in Message
-// "In the message level, the C/R bit in the command type field is set as stated in section 5.4.6.2 in GSM 07.10." 
-//   - If the C/R bit is set to 1 the message is a command
-//   - if it is set to 0 the message is a response.
-
-// temp/old messge construction
-
-// new object oriented version
-static int rfcomm_send_sabm(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);   // command
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_SABM, 0, NULL, 0);
-}
-
-static int rfcomm_send_disc(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);  // command
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DISC, 0, NULL, 0);
-}
-
-static int rfcomm_send_ua(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
-    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UA, 0, NULL, 0);
-}
-
-static int rfcomm_send_dm_pf(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
-    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DM_PF, 0, NULL, 0);
-}
-
-static int rfcomm_send_uih_msc_cmd(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
-    uint8_t payload[4]; 
-    uint8_t pos = 0;
-    payload[pos++] = BT_RFCOMM_MSC_CMD;
-    payload[pos++] = 2 << 1 | 1;  // len
-    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
-    payload[pos++] = signals;
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
-}
-
-static int rfcomm_send_uih_msc_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
-    uint8_t address = (1 << 0) | (multiplexer->outgoing<< 1);
-    uint8_t payload[4]; 
-    uint8_t pos = 0;
-    payload[pos++] = BT_RFCOMM_MSC_RSP;
-    payload[pos++] = 2 << 1 | 1;  // len
-    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
-    payload[pos++] = signals;
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
-}
-
-static int rfcomm_send_uih_pn_command(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint16_t max_frame_size){
-    uint8_t payload[10];
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
-    uint8_t pos = 0;
-    payload[pos++] = BT_RFCOMM_PN_CMD;
-    payload[pos++] = 8 << 1 | 1;  // len
-    payload[pos++] = dlci;
-    payload[pos++] = 0xf0; // pre-defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
-    payload[pos++] = 0; // priority
-    payload[pos++] = 0; // max 60 seconds ack
-    payload[pos++] = max_frame_size & 0xff; // max framesize low
-    payload[pos++] = max_frame_size >> 8;   // max framesize high
-    payload[pos++] = 0x00; // number of retransmissions
-    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
-}
-
-// "The response may not change the DLCI, the priority, the convergence layer, or the timer value." RFCOMM-tutorial.pdf
-static int rfcomm_send_uih_pn_response(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,
-                                       uint8_t priority, uint16_t max_frame_size){
-    uint8_t payload[10];
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
-    uint8_t pos = 0;
-    payload[pos++] = BT_RFCOMM_PN_RSP;
-    payload[pos++] = 8 << 1 | 1;  // len
-    payload[pos++] = dlci;
-    payload[pos++] = 0xe0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
-    payload[pos++] = priority; // priority
-    payload[pos++] = 0; // max 60 seconds ack
-    payload[pos++] = max_frame_size & 0xff; // max framesize low
-    payload[pos++] = max_frame_size >> 8;   // max framesize high
-    payload[pos++] = 0x00; // number of retransmissions
-    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
-}
-
-static int rfcomm_send_uih_rpn_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, rfcomm_rpn_data_t *rpn_data) {
-    uint8_t payload[10];
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
-    uint8_t pos = 0;
-    payload[pos++] = BT_RFCOMM_RPN_RSP;
-    payload[pos++] = 8 << 1 | 1;  // len
-    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
-    payload[pos++] = rpn_data->baud_rate;
-    payload[pos++] = rpn_data->flags;
-    payload[pos++] = rpn_data->flow_control;
-    payload[pos++] = rpn_data->xon;
-    payload[pos++] = rpn_data->xoff;
-    payload[pos++] = rpn_data->parameter_mask_0;
-    payload[pos++] = rpn_data->parameter_mask_1;
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
-}
-
-static int rfcomm_send_uih_data(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t *data, uint16_t len){
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2); 
-    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, data, len);
-}
-
-static void rfcomm_send_uih_credits(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,  uint8_t credits){
-    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) |  (dlci << 2); 
-    rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH_PF, credits, NULL, 0);
-}
-
-// MARK: RFCOMM MULTIPLEXER
-
-static void rfcomm_multiplexer_finalize(rfcomm_multiplexer_t * multiplexer){
-    
-    // remove (potential) timer
-    if (multiplexer->timer_active) {
-        run_loop_remove_timer(&multiplexer->timer);
-        multiplexer->timer_active = 0;
-    }
-    
-    // close and remove all channels
-    linked_item_t *it = (linked_item_t *) &rfcomm_channels;
-    while (it->next){
-        rfcomm_channel_t * channel = (rfcomm_channel_t *) it->next;
-        if (channel->multiplexer == multiplexer) {
-            // emit appropriate events
-            if (channel->state == RFCOMM_CHANNEL_OPEN) {
-                rfcomm_emit_channel_closed(channel);
-            } else {
-                rfcomm_emit_channel_opened(channel, RFCOMM_MULTIPLEXER_STOPPED); 
-            }
-            // remove from list
-            it->next = it->next->next;
-            // free channel struct
-            btstack_memory_rfcomm_channel_free(channel);
-        } else {
-            it = it->next;
-        }
-    }
-    
-    // keep reference to l2cap channel
-    uint16_t l2cap_cid = multiplexer->l2cap_cid;
-    
-    // remove mutliplexer
-    linked_list_remove( &rfcomm_multiplexers, (linked_item_t *) multiplexer);
-    btstack_memory_rfcomm_multiplexer_free(multiplexer);
-    
-    // close l2cap multiplexer channel, too
-    l2cap_disconnect_internal(l2cap_cid, 0x13);
-}
-
-static void rfcomm_multiplexer_timer_handler(timer_source_t *timer){
-    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t *) linked_item_get_user( (linked_item_t *) timer);
-    if (!rfcomm_multiplexer_has_channels(multiplexer)){
-        log_info( "rfcomm_multiplexer_timer_handler timeout: shutting down multiplexer!\n");
-        rfcomm_multiplexer_finalize(multiplexer);
-    }
-}
-
-static void rfcomm_multiplexer_prepare_idle_timer(rfcomm_multiplexer_t * multiplexer){
-    if (multiplexer->timer_active) {
-        run_loop_remove_timer(&multiplexer->timer);
-        multiplexer->timer_active = 0;
-    }
-    if (!rfcomm_multiplexer_has_channels(multiplexer)){
-        // start timer for multiplexer timeout check
-        run_loop_set_timer(&multiplexer->timer, RFCOMM_MULIPLEXER_TIMEOUT_MS);
-        multiplexer->timer.process = rfcomm_multiplexer_timer_handler;
-        linked_item_set_user((linked_item_t*) &multiplexer->timer, multiplexer);
-        run_loop_add_timer(&multiplexer->timer);
-        multiplexer->timer_active = 1;
-    }
-}
-
-static void rfcomm_multiplexer_opened(rfcomm_multiplexer_t *multiplexer){
-    log_info("Multiplexer up and running\n");
-    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
-    
-    rfcomm_channel_event_t event = { CH_EVT_MULTIPLEXER_READY };
-    
-    // transition of channels that wait for multiplexer 
-    linked_item_t *it;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
-        if (channel->multiplexer != multiplexer) continue;
-        rfcomm_channel_state_machine(channel, &event);
-    }        
-    
-    rfcomm_run();
-    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
-}
-
-
-/**
- * @return handled packet
- */
-static int rfcomm_multiplexer_hci_event_handler(uint8_t *packet, uint16_t size){
-    bd_addr_t event_addr;
-    uint16_t  psm;
-    uint16_t l2cap_cid;
-    hci_con_handle_t con_handle;
-    rfcomm_multiplexer_t *multiplexer = NULL;
-    switch (packet[0]) {
-            
-        // accept incoming PSM_RFCOMM connection if no multiplexer exists yet
-        case L2CAP_EVENT_INCOMING_CONNECTION:
-            // data: event(8), len(8), address(48), handle (16),  psm (16), source cid(16) dest cid(16)
-            bt_flip_addr(event_addr, &packet[2]);
-            con_handle = READ_BT_16(packet,  8);
-            psm        = READ_BT_16(packet, 10); 
-            l2cap_cid  = READ_BT_16(packet, 12); 
-
-            if (psm != PSM_RFCOMM) break;
-
-            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
-            
-            if (multiplexer) {
-                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - multiplexer already exists", l2cap_cid);
-                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
-                return 1;
-            }
-            
-            // create and inititialize new multiplexer instance (incoming)
-            multiplexer = rfcomm_multiplexer_create_for_addr(&event_addr);
-            if (!multiplexer){
-                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - no memory left", l2cap_cid);
-                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
-                return 1;
-            }
-            
-            multiplexer->con_handle = con_handle;
-            multiplexer->l2cap_cid = l2cap_cid;
-            multiplexer->state = RFCOMM_MULTIPLEXER_W4_SABM_0;
-            
-            log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => accept", l2cap_cid);
-            l2cap_accept_connection_internal(l2cap_cid);
-            return 1;
-            
-        // l2cap connection opened -> store l2cap_cid, remote_addr
-        case L2CAP_EVENT_CHANNEL_OPENED: 
-            if (READ_BT_16(packet, 11) != PSM_RFCOMM) break;
-            log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_RFCOMM\n");
-            // get multiplexer for remote addr
-            con_handle = READ_BT_16(packet, 9);
-            l2cap_cid = READ_BT_16(packet, 13);
-            bt_flip_addr(event_addr, &packet[3]);
-            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
-            if (!multiplexer) {
-                log_error("L2CAP_EVENT_CHANNEL_OPENED but no multiplexer prepared\n");
-                return 1;
-            }
-            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_CONNECT) {
-                log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection\n");
-                // wrong remote addr
-                if (BD_ADDR_CMP(event_addr, multiplexer->remote_addr)) break;
-                multiplexer->l2cap_cid = l2cap_cid;
-                multiplexer->con_handle = con_handle;
-                // send SABM #0
-                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_SABM_0;
-            } else { // multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0
-                
-                // set max frame size based on l2cap MTU
-                multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
-            }
-            return 1;
-            
-            // l2cap disconnect -> state = RFCOMM_MULTIPLEXER_CLOSED;
-            
-        case L2CAP_EVENT_CREDITS:
-            // data: event(8), len(8), local_cid(16), credits(8)
-            l2cap_cid = READ_BT_16(packet, 2);
-            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
-            if (!multiplexer) break;
-            multiplexer->l2cap_credits += packet[4];
-            
-            // log_info("L2CAP_EVENT_CREDITS: %u (now %u)\n", packet[4], multiplexer->l2cap_credits);
-
-            // new credits, continue with signaling
-            rfcomm_run();
-            
-            if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) break;
-            rfcomm_hand_out_credits();
-            return 1;
-        
-        case DAEMON_EVENT_HCI_PACKET_SENT:
-            // testing DMA done code
-            rfcomm_run();
-            break;
-            
-        case L2CAP_EVENT_CHANNEL_CLOSED:
-            // data: event (8), len(8), channel (16)
-            l2cap_cid = READ_BT_16(packet, 2);
-            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
-            if (!multiplexer) break;
-            switch (multiplexer->state) {
-                case RFCOMM_MULTIPLEXER_W4_SABM_0:
-                case RFCOMM_MULTIPLEXER_W4_UA_0:
-                case RFCOMM_MULTIPLEXER_OPEN:
-                    rfcomm_multiplexer_finalize(multiplexer);
-                    return 1;
-                default:
-                    break;
-            }
-            break;
-        default:
-            break;
-    }
-    return 0;
-}
-
-static int rfcomm_multiplexer_l2cap_packet_handler(uint16_t channel, uint8_t *packet, uint16_t size){
-    
-    // get or create a multiplexer for a certain device
-    rfcomm_multiplexer_t *multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
-    if (!multiplexer) return 0;
-    
-    // but only care for multiplexer control channel
-    uint8_t frame_dlci = packet[0] >> 2;
-    if (frame_dlci) return 0;
-    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
-    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
-    const uint8_t payload_offset = 3 + length_offset + credit_offset;
-    switch (packet[1]){
-            
-        case BT_RFCOMM_SABM:
-            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0){
-                log_info("Received SABM #0\n");
-                multiplexer->outgoing = 0;
-                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0;
-                return 1;
-            }
-            break;
-            
-        case BT_RFCOMM_UA:
-            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_UA_0) {
-                // UA #0 -> send UA #0, state = RFCOMM_MULTIPLEXER_OPEN
-                log_info("Received UA #0 \n");
-                rfcomm_multiplexer_opened(multiplexer);
-                return 1;
-            }
-            break;
-            
-        case BT_RFCOMM_DISC:
-            // DISC #0 -> send UA #0, close multiplexer
-            log_info("Received DISC #0, (ougoing = %u)\n", multiplexer->outgoing);
-            multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC;
-            return 1;
-            
-        case BT_RFCOMM_DM:
-            // DM #0 - we shouldn't get this, just give up
-            log_info("Received DM #0\n");
-            log_info("-> Closing down multiplexer\n");
-            rfcomm_multiplexer_finalize(multiplexer);
-            return 1;
-            
-        case BT_RFCOMM_UIH:
-            if (packet[payload_offset] == BT_RFCOMM_CLD_CMD){
-                // Multiplexer close down (CLD) -> close mutliplexer
-                log_info("Received Multiplexer close down command\n");
-                log_info("-> Closing down multiplexer\n");
-                rfcomm_multiplexer_finalize(multiplexer);
-                return 1;
-            }
-            break;
-            
-        default:
-            break;
-            
-    }
-    return 0;
-}
-
-static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event){
-    
-    // process stored DM responses
-    if (multiplexer->send_dm_for_dlci){
-        rfcomm_send_dm_pf(multiplexer, multiplexer->send_dm_for_dlci);
-        multiplexer->send_dm_for_dlci = 0;
-    }
-
-    switch (multiplexer->state) {
-        case RFCOMM_MULTIPLEXER_SEND_SABM_0:
-            switch (event) {
-                case MULT_EV_READY_TO_SEND:
-                    log_info("Sending SABM #0 - (multi 0x%p)\n", multiplexer);
-                    multiplexer->state = RFCOMM_MULTIPLEXER_W4_UA_0;
-                    rfcomm_send_sabm(multiplexer, 0);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case RFCOMM_MULTIPLEXER_SEND_UA_0:
-            switch (event) {
-                case MULT_EV_READY_TO_SEND:
-                    log_info("Sending UA #0\n");
-                    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
-                    rfcomm_send_ua(multiplexer, 0);
-                    rfcomm_multiplexer_opened(multiplexer);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC:
-            switch (event) {
-                case MULT_EV_READY_TO_SEND:
-                    log_info("Sending UA #0\n");
-                    log_info("Closing down multiplexer\n");
-                    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
-                    rfcomm_send_ua(multiplexer, 0);
-                    rfcomm_multiplexer_finalize(multiplexer);
-                    // try to detect authentication errors: drop link key if multiplexer closed before first channel got opened
-                    if (!multiplexer->at_least_one_connection){
-                        log_info("TODO: no connections established - delete link key prophylactically\n");
-                        // hci_send_cmd(&hci_delete_stored_link_key, multiplexer->remote_addr);
-                    }
-                default:
-                    break;
-            }
-            break;
-        default:
-            break;
-    }
-}
-
-// MARK: RFCOMM CHANNEL
-
-static void rfcomm_hand_out_credits(void){
-    linked_item_t * it;
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
-        if (channel->state != RFCOMM_CHANNEL_OPEN) {
-            // log_info("RFCOMM_EVENT_CREDITS: multiplexer not open\n");
-            continue;
-        }
-        if (channel->packets_granted) {
-            // log_info("RFCOMM_EVENT_CREDITS: already packets granted\n");
-            continue;
-        }
-        if (!channel->credits_outgoing) {
-            // log_info("RFCOMM_EVENT_CREDITS: no outgoing credits\n");
-            continue;
-        }
-        if (!channel->multiplexer->l2cap_credits){
-            // log_info("RFCOMM_EVENT_CREDITS: no l2cap credits\n");
-            continue;
-        }
-        // channel open, multiplexer has l2cap credits and we didn't hand out credit before -> go!
-        // log_info("RFCOMM_EVENT_CREDITS: 1\n");
-        channel->packets_granted += 1;
-        rfcomm_emit_credits(channel, 1);
-    }        
-}
-
-static void rfcomm_channel_send_credits(rfcomm_channel_t *channel, uint8_t credits){
-    rfcomm_send_uih_credits(channel->multiplexer, channel->dlci, credits);
-    channel->credits_incoming += credits;
-    
-    rfcomm_emit_credit_status(channel);
-}
-
-static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
-    
-    log_info("rfcomm_channel_opened!\n");
-    
-    rfChannel->state = RFCOMM_CHANNEL_OPEN;
-    rfcomm_emit_channel_opened(rfChannel, 0);
-    rfcomm_hand_out_credits();
-
-    // remove (potential) timer
-    rfcomm_multiplexer_t *multiplexer = rfChannel->multiplexer;
-    if (multiplexer->timer_active) {
-        run_loop_remove_timer(&multiplexer->timer);
-        multiplexer->timer_active = 0;
-    }
-    // hack for problem detecting authentication failure
-    multiplexer->at_least_one_connection = 1;
-    
-    // start next connection request if pending
-    rfcomm_run();
-}
-
-static void rfcomm_channel_packet_handler_uih(rfcomm_multiplexer_t *multiplexer, uint8_t * packet, uint16_t size){
-    const uint8_t frame_dlci = packet[0] >> 2;
-    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
-    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
-    const uint8_t payload_offset = 3 + length_offset + credit_offset;
-
-    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, frame_dlci);
-    if (!channel) return;
-    
-    // handle new outgoing credits
-    if (packet[1] == BT_RFCOMM_UIH_PF) {
-        
-        // add them
-        uint16_t new_credits = packet[3+length_offset];
-        channel->credits_outgoing += new_credits;
-        log_info( "RFCOMM data UIH_PF, new credits: %u, now %u\n", new_credits, channel->credits_outgoing);
-
-        // notify channel statemachine 
-        rfcomm_channel_event_t channel_event = { CH_EVT_RCVD_CREDITS };
-        rfcomm_channel_state_machine(channel, &channel_event);
-    }
-    
-    // contains payload?
-    if (size - 1 > payload_offset){
-
-        // log_info( "RFCOMM data UIH_PF, size %u, channel %p\n", size-payload_offset-1, rfChannel->connection);
-
-        // decrease incoming credit counter
-        if (channel->credits_incoming > 0){
-            channel->credits_incoming--;
-        }
-        
-        // deliver payload
-        (*app_packet_handler)(channel->connection, RFCOMM_DATA_PACKET, channel->rfcomm_cid,
-                              &packet[payload_offset], size-payload_offset-1);
-    }
-    
-    // automatically provide new credits to remote device, if no incoming flow control
-    if (!channel->incoming_flow_control && channel->credits_incoming < 5){
-        channel->new_credits_incoming = 0x30;
-    }    
-    
-    rfcomm_emit_credit_status(channel);
-    
-    // we received new RFCOMM credits, hand them out if possible
-    rfcomm_hand_out_credits();
-}
-
-static void rfcomm_channel_accept_pn(rfcomm_channel_t *channel, rfcomm_channel_event_pn_t *event){
-    // priority of client request
-    channel->pn_priority = event->priority;
-    
-    // new credits
-    channel->credits_outgoing = event->credits_outgoing;
-    
-    // negotiate max frame size
-    if (channel->max_frame_size > channel->multiplexer->max_frame_size) {
-        channel->max_frame_size = channel->multiplexer->max_frame_size;
-    }
-    if (channel->max_frame_size > event->max_frame_size) {
-        channel->max_frame_size = event->max_frame_size;
-    }
-    
-}
-
-static void rfcomm_channel_finalize(rfcomm_channel_t *channel){
-
-    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
-
-    // remove from list
-    linked_list_remove( &rfcomm_channels, (linked_item_t *) channel);
-
-    // free channel
-    btstack_memory_rfcomm_channel_free(channel);
-    
-    // update multiplexer timeout after channel was removed from list
-    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
-}
-
-static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event){
-
-    // TODO: if client max frame size is smaller than RFCOMM_DEFAULT_SIZE, send PN
-
-    
-    // lookup existing channel
-    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, dlci);
-
-    // log_info("rfcomm_channel_state_machine_2 lookup dlci #%u = 0x%08x - event %u\n", dlci, (int) channel, event->type);
-
-    if (channel) {
-        rfcomm_channel_state_machine(channel, event);
-        return;
-    }
-    
-    // service registered?
-    rfcomm_service_t * service = rfcomm_service_for_channel(dlci >> 1);
-    // log_info("rfcomm_channel_state_machine_2 service dlci #%u = 0x%08x\n", dlci, (int) service);
-    if (!service) {
-        // discard request by sending disconnected mode
-        multiplexer->send_dm_for_dlci = dlci;
-        return;
-    }
-
-    // create channel for some events
-    switch (event->type) {
-        case CH_EVT_RCVD_SABM:
-        case CH_EVT_RCVD_PN:
-        case CH_EVT_RCVD_RPN_REQ:
-        case CH_EVT_RCVD_RPN_CMD:
-            // setup incoming channel
-            channel = rfcomm_channel_create(multiplexer, service, dlci >> 1);
-            if (!channel){
-                // discard request by sending disconnected mode
-                multiplexer->send_dm_for_dlci = dlci;
-            }
-            break;
-        default:
-            break;
-    }
-
-    if (!channel) {
-        // discard request by sending disconnected mode
-        multiplexer->send_dm_for_dlci = dlci;
-        return;
-    }
-    channel->connection = service->connection;
-    rfcomm_channel_state_machine(channel, event);
-}
-
-void rfcomm_channel_packet_handler(rfcomm_multiplexer_t * multiplexer,  uint8_t *packet, uint16_t size){
-    
-    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
-    const uint8_t frame_dlci = packet[0] >> 2;
-    uint8_t message_dlci; // used by commands in UIH(_PF) packets 
-    uint8_t message_len;  //   "
-    
-    // rfcomm: (1) command/control
-    // -- credits_offset = 1 if command == BT_RFCOMM_UIH_PF
-    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
-    // rfcomm: (2) length. if bit 0 is cleared, 2 byte length is used. (little endian)
-    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
-    // rfcomm: (3+length_offset) credits if credits_offset == 1
-    // rfcomm: (3+length_offest+credits_offset)
-    const uint8_t payload_offset = 3 + length_offset + credit_offset;
-    
-    rfcomm_channel_event_t event;
-    rfcomm_channel_event_pn_t event_pn;
-    rfcomm_channel_event_rpn_t event_rpn;
-
-    // switch by rfcomm message type
-    switch(packet[1]) {
-            
-        case BT_RFCOMM_SABM:
-            event.type = CH_EVT_RCVD_SABM;
-            log_info("Received SABM #%u\n", frame_dlci);
-            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
-            break;
-            
-        case BT_RFCOMM_UA:
-            event.type = CH_EVT_RCVD_UA;
-            log_info("Received UA #%u - channel opened\n",frame_dlci);
-            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
-            break;
-            
-        case BT_RFCOMM_DISC:
-            event.type = CH_EVT_RCVD_DISC;
-            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
-            break;
-            
-        case BT_RFCOMM_DM:
-        case BT_RFCOMM_DM_PF:
-            event.type = CH_EVT_RCVD_DM;
-            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
-            break;
-            
-        case BT_RFCOMM_UIH_PF:
-        case BT_RFCOMM_UIH:
-
-            message_len  = packet[payload_offset+1] >> 1;
-
-            switch (packet[payload_offset]) {
-                case BT_RFCOMM_PN_CMD:
-                    message_dlci = packet[payload_offset+2];
-                    event_pn.super.type = CH_EVT_RCVD_PN;
-                    event_pn.priority = packet[payload_offset+4];
-                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
-                    event_pn.credits_outgoing = packet[payload_offset+9];
-                    log_info("Received UIH Parameter Negotiation Command for #%u\n", message_dlci);
-                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
-                    break;
-                    
-                case BT_RFCOMM_PN_RSP:
-                    message_dlci = packet[payload_offset+2];
-                    event_pn.super.type = CH_EVT_RCVD_PN_RSP;
-                    event_pn.priority = packet[payload_offset+4];
-                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
-                    event_pn.credits_outgoing = packet[payload_offset+9];
-                    log_info("UIH Parameter Negotiation Response max frame %u, credits %u\n",
-                            event_pn.max_frame_size, event_pn.credits_outgoing);
-                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
-                    break;
-                    
-                case BT_RFCOMM_MSC_CMD: 
-                    message_dlci = packet[payload_offset+2] >> 2;
-                    event.type = CH_EVT_RCVD_MSC_CMD;
-                    log_info("Received MSC CMD for #%u, \n", message_dlci);
-                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
-                    break;
-                    
-                case BT_RFCOMM_MSC_RSP:
-                    message_dlci = packet[payload_offset+2] >> 2;
-                    event.type = CH_EVT_RCVD_MSC_RSP;
-                    log_info("Received MSC RSP for #%u\n", message_dlci);
-                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
-                    break;
-                    
-                case BT_RFCOMM_RPN_CMD:
-                    message_dlci = packet[payload_offset+2] >> 2;
-                    switch (message_len){
-                        case 1:
-                            log_info("Received Remote Port Negotiation for #%u\n", message_dlci);
-                            event.type = CH_EVT_RCVD_RPN_REQ;
-                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
-                            break;
-                        case 8:
-                            log_info("Received Remote Port Negotiation (Info) for #%u\n", message_dlci);
-                            event_rpn.super.type = CH_EVT_RCVD_RPN_CMD;
-                            event_rpn.data.baud_rate = packet[payload_offset+3];
-                            event_rpn.data.flags = packet[payload_offset+4];
-                            event_rpn.data.flow_control = packet[payload_offset+5];
-                            event_rpn.data.xon  = packet[payload_offset+6];
-                            event_rpn.data.xoff = packet[payload_offset+7];
-                            event_rpn.data.parameter_mask_0 = packet[payload_offset+8];
-                            event_rpn.data.parameter_mask_1 = packet[payload_offset+9];
-                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_rpn);
-                            break;
-                        default:
-                            break;
-                    }
-                    break;
-                    
-                default:
-                    log_error("Received unknown UIH packet - 0x%02x\n", packet[payload_offset]); 
-                    break;
-            }
-            break;
-            
-        default:
-            log_error("Received unknown RFCOMM message type %x\n", packet[1]);
-            break;
-    }
-    
-    // trigger next action - example W4_PN_RSP: transition to SEND_SABM which only depends on "can send"
-    rfcomm_run();
-}
-
-void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    
-    // multiplexer handler
-    int handled = 0;
-    switch (packet_type) {
-        case HCI_EVENT_PACKET:
-            handled = rfcomm_multiplexer_hci_event_handler(packet, size);
-            break;
-        case L2CAP_DATA_PACKET:
-            handled = rfcomm_multiplexer_l2cap_packet_handler(channel, packet, size);
-            break;
-        default:
-            break;
-    }
-    
-    if (handled) {
-        rfcomm_run();
-        return;
-    }
-    
-    // we only handle l2cap packet over open multiplexer channel now
-    if (packet_type != L2CAP_DATA_PACKET) {
-        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
-        return;
-    }
-    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
-    if (!multiplexer || multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
-        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
-        return;
-    }
-    
-    // channel data ?
-    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
-    const uint8_t frame_dlci = packet[0] >> 2;
-    
-    if (frame_dlci && (packet[1] == BT_RFCOMM_UIH || packet[1] == BT_RFCOMM_UIH_PF)) {
-        rfcomm_channel_packet_handler_uih(multiplexer, packet, size);
-        rfcomm_run();
-        return;
-    }
-     
-    rfcomm_channel_packet_handler(multiplexer, packet, size);
-}
-
-static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel){
-    // log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u \n", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
-    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP) == 0) return 0;
-    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP) == 0) return 0;
-    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS) == 0) return 0;
-    if (channel->credits_outgoing == 0) return 0;
-    
-    return 1;
-}
-
-static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event){
-    
-    // log_info("rfcomm_channel_state_machine: state %u, state_var %04x, event %u\n", channel->state, channel->state_var ,event->type);
-    
-    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
-    
-    // TODO: integrate in common switch
-    if (event->type == CH_EVT_RCVD_DISC){
-        rfcomm_emit_channel_closed(channel);
-        channel->state = RFCOMM_CHANNEL_SEND_UA_AFTER_DISC;
-        return;
-    }
-    
-    // TODO: integrate in common switch
-    if (event->type == CH_EVT_RCVD_DM){
-        log_info("Received DM message for #%u\n", channel->dlci);
-        log_info("-> Closing channel locally for #%u\n", channel->dlci);
-        rfcomm_emit_channel_closed(channel);
-        rfcomm_channel_finalize(channel);
-        return;
-    }
-    
-    // remote port negotiation command - just accept everything for now
-    //
-    // "The RPN command can be used before a new DLC is opened and should be used whenever the port settings change."
-    // "The RPN command is specified as optional in TS 07.10, but it is mandatory to recognize and respond to it in RFCOMM. 
-    //   (Although the handling of individual settings are implementation-dependent.)"
-    //
-    
-    // TODO: integrate in common switch
-    if (event->type == CH_EVT_RCVD_RPN_CMD){
-        // control port parameters
-        rfcomm_channel_event_rpn_t *event_rpn = (rfcomm_channel_event_rpn_t*) event;
-        memcpy(&channel->rpn_data, &event_rpn->data, sizeof(rfcomm_rpn_data_t));
-        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
-        return;
-    }
-    
-    // TODO: integrate in common switch
-    if (event->type == CH_EVT_RCVD_RPN_REQ){
-        // default rpn rsp
-        rfcomm_rpn_data_t rpn_data;
-        rpn_data.baud_rate = 0xa0;        /* 9600 bps */
-        rpn_data.flags = 0x03;            /* 8-n-1 */
-        rpn_data.flow_control = 0;        /* no flow control */
-        rpn_data.xon  = 0xd1;             /* XON */
-        rpn_data.xoff = 0xd3;             /* XOFF */
-        rpn_data.parameter_mask_0 = 0x7f; /* parameter mask, all values set */
-        rpn_data.parameter_mask_1 = 0x3f; /* parameter mask, all values set */
-        memcpy(&channel->rpn_data, &rpn_data, sizeof(rfcomm_rpn_data_t));
-        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
-        return;
-    }
-    
-    // TODO: integrate in common swich
-    if (event->type == CH_EVT_READY_TO_SEND){
-        if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP){
-            log_info("Sending Remote Port Negotiation RSP for #%u\n", channel->dlci);
-            channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
-            rfcomm_send_uih_rpn_rsp(multiplexer, channel->dlci, &channel->rpn_data);
-            return;
-        }
-    }
-    
-    rfcomm_channel_event_pn_t * event_pn = (rfcomm_channel_event_pn_t*) event;
-    
-    switch (channel->state) {
-        case RFCOMM_CHANNEL_CLOSED:
-            switch (event->type){
-                case CH_EVT_RCVD_SABM:
-                    log_info("-> Inform app\n");
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
-                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
-                    rfcomm_emit_connection_request(channel);
-                    break;
-                case CH_EVT_RCVD_PN:
-                    rfcomm_channel_accept_pn(channel, event_pn);
-                    log_info("-> Inform app\n");
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
-                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
-                    rfcomm_emit_connection_request(channel);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_INCOMING_SETUP:
-            switch (event->type){
-                case CH_EVT_RCVD_SABM:
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
-                    }
-                    break;
-                case CH_EVT_RCVD_PN:
-                    rfcomm_channel_accept_pn(channel, event_pn);
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
-                    }
-                    break;
-                case CH_EVT_READY_TO_SEND:
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP){
-                        log_info("Sending UIH Parameter Negotiation Respond for #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
-                        rfcomm_send_uih_pn_response(multiplexer, channel->dlci, channel->pn_priority, channel->max_frame_size);
-                    }
-                    else if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_UA){
-                        log_info("Sending UA #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
-                        rfcomm_send_ua(multiplexer, channel->dlci);
-                    }
-                    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) && (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM)) {
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
-                        channel->state = RFCOMM_CHANNEL_DLC_SETUP;
-                    } 
-                    break;
-                    
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_W4_MULTIPLEXER:
-            switch (event->type) {
-                case CH_EVT_MULTIPLEXER_READY:
-                    log_info("Muliplexer opened, sending UIH PN next\n");
-                    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_SEND_UIH_PN:
-            switch (event->type) {
-                case CH_EVT_READY_TO_SEND:
-                    log_info("Sending UIH Parameter Negotiation Command for #%u (channel 0x%p)\n", channel->dlci, channel );
-                    channel->state = RFCOMM_CHANNEL_W4_PN_RSP;
-                    rfcomm_send_uih_pn_command(multiplexer, channel->dlci, channel->max_frame_size);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_W4_PN_RSP:
-            switch (event->type){
-                case CH_EVT_RCVD_PN_RSP:
-                    // update max frame size
-                    if (channel->max_frame_size > event_pn->max_frame_size) {
-                        channel->max_frame_size = event_pn->max_frame_size;
-                    }
-                    // new credits
-                    channel->credits_outgoing = event_pn->credits_outgoing;
-                    channel->state = RFCOMM_CHANNEL_SEND_SABM_W4_UA;
-                    break;
-                default:
-                    break;
-            }
-            break;
-
-        case RFCOMM_CHANNEL_SEND_SABM_W4_UA:
-            switch (event->type) {
-                case CH_EVT_READY_TO_SEND:
-                    log_info("Sending SABM #%u\n", channel->dlci);
-                    channel->state = RFCOMM_CHANNEL_W4_UA;
-                    rfcomm_send_sabm(multiplexer, channel->dlci);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_W4_UA:
-            switch (event->type){
-                case CH_EVT_RCVD_UA:
-                    channel->state = RFCOMM_CHANNEL_DLC_SETUP;
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_DLC_SETUP:
-            switch (event->type){
-                case CH_EVT_RCVD_MSC_CMD:
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD;
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
-                    break;
-                case CH_EVT_RCVD_MSC_RSP:
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP;
-                    break;
-                    
-                case CH_EVT_READY_TO_SEND:
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD){
-                        log_info("Sending MSC CMD for #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD;
-                        rfcomm_send_uih_msc_cmd(multiplexer, channel->dlci , 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
-                        break;
-                    }
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
-                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP;
-                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
-                        break;
-                    }
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS){
-                        log_info("Providing credits for #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
-                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS;
-                        if (channel->new_credits_incoming) {
-                            uint8_t new_credits = channel->new_credits_incoming;
-                            channel->new_credits_incoming = 0;
-                            rfcomm_channel_send_credits(channel, new_credits);
-                        }
-                        break;
-
-                    }
-                    break;
-                default:
-                    break;
-            }
-            // finally done?
-            if (rfcomm_channel_ready_for_open(channel)){
-                channel->state = RFCOMM_CHANNEL_OPEN;
-                rfcomm_channel_opened(channel);
-            }
-            break;
-        
-        case RFCOMM_CHANNEL_OPEN:
-            switch (event->type){
-                case CH_EVT_RCVD_MSC_CMD:
-                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
-                    break;
-                case CH_EVT_READY_TO_SEND:
-                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
-                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
-                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
-                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
-                        break;
-                    }
-                    if (channel->new_credits_incoming) {
-                        uint8_t new_credits = channel->new_credits_incoming;
-                        channel->new_credits_incoming = 0;
-                        rfcomm_channel_send_credits(channel, new_credits);
-                        break;
-                    }
-                    break;
-                case CH_EVT_RCVD_CREDITS: {
-                    // notify daemon -> might trigger re-try of parked connections
-                    uint8_t event[1] = { DAEMON_EVENT_NEW_RFCOMM_CREDITS };
-                    (*app_packet_handler)(channel->connection, DAEMON_EVENT_PACKET, channel->rfcomm_cid, event, sizeof(event));
-                    break;
-                }  
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_SEND_DM:
-            switch (event->type) {
-                case CH_EVT_READY_TO_SEND:
-                    log_info("Sending DM_PF for #%u\n", channel->dlci);
-                    // don't emit channel closed - channel was never open
-                    channel->state = RFCOMM_CHANNEL_CLOSED;
-                    rfcomm_send_dm_pf(multiplexer, channel->dlci);
-                    rfcomm_channel_finalize(channel);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_SEND_DISC:
-            switch (event->type) {
-                case CH_EVT_READY_TO_SEND:
-                    channel->state = RFCOMM_CHANNEL_CLOSED;
-                    rfcomm_send_disc(multiplexer, channel->dlci);
-                    rfcomm_emit_channel_closed(channel);
-                    rfcomm_channel_finalize(channel);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_CHANNEL_SEND_UA_AFTER_DISC:
-            switch (event->type) {
-                case CH_EVT_READY_TO_SEND:
-                    log_info("Sending UA after DISC for #%u\n", channel->dlci);
-                    channel->state = RFCOMM_CHANNEL_CLOSED;
-                    rfcomm_send_ua(multiplexer, channel->dlci);
-                    rfcomm_channel_finalize(channel);
-                    break;
-                default:
-                    break;
-            }
-            break;
-            
-        default:
-            break;
-    }
-}
-
-
-// MARK: RFCOMM RUN
-// process outstanding signaling tasks
-static void rfcomm_run(void){
-    
-    linked_item_t *it;
-    linked_item_t *next;
-    
-    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = next){
-
-        next = it->next;    // be prepared for removal of channel in state machine
-        
-        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
-        
-        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) {
-            // log_info("rfcomm_run cannot send l2cap packet for #%u, credits %u\n", multiplexer->l2cap_cid, multiplexer->l2cap_credits);
-            continue;
-        }
-        // log_info("rfcomm_run: multi 0x%08x, state %u\n", (int) multiplexer, multiplexer->state);
-
-        rfcomm_multiplexer_state_machine(multiplexer, MULT_EV_READY_TO_SEND);
-    }
-
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = next){
-
-        next = it->next;    // be prepared for removal of channel in state machine
-
-        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
-        rfcomm_multiplexer_t * multiplexer = channel->multiplexer;
-        
-        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) continue;
-     
-        rfcomm_channel_event_t event = { CH_EVT_READY_TO_SEND };
-        rfcomm_channel_state_machine(channel, &event);
-    }
-}
-
-// MARK: RFCOMM BTstack API
-
-void rfcomm_init(void){
-    rfcomm_client_cid_generator = 0;
-    rfcomm_multiplexers = NULL;
-    rfcomm_services     = NULL;
-    rfcomm_channels     = NULL;
-}
-
-// register packet handler
-void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
-                                                    uint16_t channel, uint8_t *packet, uint16_t size)){
-    app_packet_handler = handler;
-}
-
-// send packet over specific channel
-int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
-
-    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
-    if (!channel){
-        log_error("rfcomm_send_internal cid %u doesn't exist!\n", rfcomm_cid);
-        return 0;
-    }
-    
-    if (!channel->credits_outgoing){
-        log_info("rfcomm_send_internal cid %u, no rfcomm outgoing credits!\n", rfcomm_cid);
-        return RFCOMM_NO_OUTGOING_CREDITS;
-    }
-
-    if (!channel->packets_granted){
-        log_info("rfcomm_send_internal cid %u, no rfcomm credits granted!\n", rfcomm_cid);
-        return RFCOMM_NO_OUTGOING_CREDITS;
-    }
-    
-    // log_info("rfcomm_send_internal: len %u... outgoing credits %u, l2cap credit %us, granted %u\n",
-    //        len, channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
-    
-
-    // send might cause l2cap to emit new credits, update counters first
-    channel->credits_outgoing--;
-    int packets_granted_decreased = 0;
-    if (channel->packets_granted) {
-        channel->packets_granted--;
-        packets_granted_decreased++;
-    }
-    
-    int result = rfcomm_send_uih_data(channel->multiplexer, channel->dlci, data, len);
-    
-    if (result != 0) {
-        channel->credits_outgoing++;
-        channel->packets_granted += packets_granted_decreased;
-        log_info("rfcomm_send_internal: error %d\n", result);
-        return result;
-    }
-    
-    // log_info("rfcomm_send_internal: now outgoing credits %u, l2cap credit %us, granted %u\n",
-    //        channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
-
-    rfcomm_hand_out_credits();
-    
-    return result;
-}
-
-void rfcomm_create_channel2(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t incoming_flow_control, uint8_t initial_credits){
-    log_info("rfcomm_create_channel_internal to %s, at channel #%02x, flow control %u, init credits %u\n",  bd_addr_to_str(*addr), server_channel,
-             incoming_flow_control, initial_credits);
-    
-    // create new multiplexer if necessary
-    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_addr(addr);
-    if (!multiplexer) {
-        multiplexer = rfcomm_multiplexer_create_for_addr(addr);
-        if (!multiplexer){
-            rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
-            return;
-        }
-        multiplexer->outgoing = 1;
-        multiplexer->state = RFCOMM_MULTIPLEXER_W4_CONNECT;
-    }
-    
-    // prepare channel
-    rfcomm_channel_t * channel = rfcomm_channel_create(multiplexer, NULL, server_channel);
-    if (!channel){
-        rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
-        return;
-    }
-    channel->connection = connection;
-    channel->incoming_flow_control = incoming_flow_control;
-    channel->new_credits_incoming  = initial_credits;
-    
-    // start multiplexer setup
-    if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
-        
-        channel->state = RFCOMM_CHANNEL_W4_MULTIPLEXER;
-        
-        l2cap_create_channel_internal(connection, rfcomm_packet_handler, *addr, PSM_RFCOMM, l2cap_max_mtu());
-        
-        return;
-    }
-    
-    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
-    
-    // start connecting, if multiplexer is already up and running
-    rfcomm_run();
-}
-
-void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits){
-    rfcomm_create_channel2(connection, addr, server_channel, 1, initial_credits);
-}
-
-void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t server_channel){
-    rfcomm_create_channel2(connection, addr, server_channel, 0, 0x30);
-}
-
-void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
-    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
-    if (channel) {
-        channel->state = RFCOMM_CHANNEL_SEND_DISC;
-    }
-    
-    // process
-    rfcomm_run();
-}
-
-
-void rfcomm_register_service2(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){
-    // check if already registered
-    rfcomm_service_t * service = rfcomm_service_for_channel(channel);
-    if (service){
-        rfcomm_emit_service_registered(connection, RFCOMM_CHANNEL_ALREADY_REGISTERED, channel);
-        return;
-    }
-    
-    // alloc structure
-    service = (rfcomm_service_t*)btstack_memory_rfcomm_service_get();
-    if (!service) {
-        rfcomm_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, channel);
-        return;
-    }
-    
-    // register with l2cap if not registered before, max MTU
-    if (linked_list_empty(&rfcomm_services)){
-        l2cap_register_service_internal(NULL, rfcomm_packet_handler, PSM_RFCOMM, 0xffff);
-    }
-    
-    // fill in 
-    service->connection     = connection;
-    service->server_channel = channel;
-    service->max_frame_size = max_frame_size;
-    service->incoming_flow_control = incoming_flow_control;
-    service->incoming_initial_credits = initial_credits;
-    
-    // add to services list
-    linked_list_add(&rfcomm_services, (linked_item_t *) service);
-    
-    // done
-    rfcomm_emit_service_registered(connection, 0, channel);
-}
-
-void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits){
-    rfcomm_register_service2(connection, channel, max_frame_size, 1, initial_credits);
-}
-
-void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
-    rfcomm_register_service2(connection, channel, max_frame_size, 0, 0x30);
-}
-
-void rfcomm_unregister_service_internal(uint8_t service_channel){
-    rfcomm_service_t *service = rfcomm_service_for_channel(service_channel);
-    if (!service) return;
-    linked_list_remove(&rfcomm_services, (linked_item_t *) service);
-    btstack_memory_rfcomm_service_free(service);
-    
-    // unregister if no services active
-    if (linked_list_empty(&rfcomm_services)){
-        // bt_send_cmd(&l2cap_unregister_service, PSM_RFCOMM);
-        l2cap_unregister_service_internal(NULL, PSM_RFCOMM);
-    }
-}
-
-void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
-    log_info("Received Accept Connction\n");
-    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
-    if (!channel) return;
-    switch (channel->state) {
-        case RFCOMM_CHANNEL_INCOMING_SETUP:
-            channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED;
-            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_PN){
-                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
-            }
-            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM){
-                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
-            }
-            break;
-        default:
-            break;
-    }
-
-    // process
-    rfcomm_run();
-}
-
-void rfcomm_decline_connection_internal(uint16_t rfcomm_cid){
-    log_info("Received Decline Connction\n");
-    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
-    if (!channel) return;
-    switch (channel->state) {
-        case RFCOMM_CHANNEL_INCOMING_SETUP:
-            channel->state = RFCOMM_CHANNEL_SEND_DM;
-            break;
-        default:
-            break;
-    }
-
-    // process
-    rfcomm_run();
-}
-
-void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits){
-    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
-    if (!channel) return;
-    if (!channel->incoming_flow_control) return;
-    channel->new_credits_incoming += credits;
-
-    // process
-    rfcomm_run();
-}
-
-//
-void rfcomm_close_connection(void *connection){
-    linked_item_t *it;
-    
-    // close open channels
-    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
-        rfcomm_channel_t * channel = (rfcomm_channel_t *)it;
-        if (channel->connection != connection) continue;
-        channel->state = RFCOMM_CHANNEL_SEND_DISC;
-    }
-    
-    // unregister services
-    it = (linked_item_t *) &rfcomm_services;
-    while (it->next) {
-        rfcomm_service_t * service = (rfcomm_service_t *) it->next;
-        if (service->connection == connection){
-            it->next = it->next->next;
-            btstack_memory_rfcomm_service_free(service);
-        } else {
-            it = it->next;
-        }
-    }
-
-    // process
-    rfcomm_run();
-}
-
-
-
-
--- a/BTstack/rfcomm.h	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/rfcomm.h	Thu Feb 07 14:01:01 2013 +0000
@@ -102,7 +102,6 @@
     
 } RFCOMM_CHANNEL_STATE;
 
-/*
 typedef enum {
     RFCOMM_CHANNEL_STATE_VAR_NONE            = 0,
     RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED = 1 << 0,
@@ -125,31 +124,6 @@
     RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP    = 1 << 14,
     RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS    = 1 << 15,
 } RFCOMM_CHANNEL_STATE_VAR;
-*/
-
-enum {
-    RFCOMM_CHANNEL_STATE_VAR_NONE            = 0,
-    RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED = 1 << 0,
-    RFCOMM_CHANNEL_STATE_VAR_RCVD_PN         = 1 << 1,
-    RFCOMM_CHANNEL_STATE_VAR_RCVD_RPN        = 1 << 2,
-    RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM       = 1 << 3,
-    
-    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD    = 1 << 4,
-    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP    = 1 << 5,
-    RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP     = 1 << 6,
-    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_INFO   = 1 << 7,
-    
-    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP    = 1 << 8,
-    RFCOMM_CHANNEL_STATE_VAR_SEND_UA         = 1 << 9,
-    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD    = 1 << 10,
-    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP    = 1 << 11,
-    
-    RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS    = 1 << 12,
-    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD    = 1 << 13,
-    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP    = 1 << 14,
-    RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS    = 1 << 15,
-};
-typedef uint16_t RFCOMM_CHANNEL_STATE_VAR;
 
 typedef enum {
     CH_EVT_RCVD_SABM = 1,
@@ -227,7 +201,7 @@
     timer_source_t   timer;
     int              timer_active;
     
-    RFCOMM_MULTIPLEXER_STATE state;    
+    RFCOMM_MULTIPLEXER_STATE state; 
     
     uint16_t  l2cap_cid;
     uint8_t   l2cap_credits;
--- a/BTstack/run_loop_embedded.c	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/run_loop_embedded.c	Thu Feb 07 14:01:01 2013 +0000
@@ -52,10 +52,10 @@
  */
 
 
-#include <btstack/run_loop.h>
-#include <btstack/linked_list.h>
-#include <btstack/hal_tick.h>
-#include <btstack/hal_cpu.h>
+#include "btstack/run_loop.h"
+#include "btstack/linked_list.h"
+#include "btstack/hal_tick.h"
+#include "btstack/hal_cpu.h"
 
 #include "run_loop_private.h"
 #include "debug.h"
--- a/BTstack/run_loop_private.h	Tue Jun 26 14:27:45 2012 +0000
+++ b/BTstack/run_loop_private.h	Thu Feb 07 14:01:01 2013 +0000
@@ -42,7 +42,7 @@
 
 #pragma once
 
-#include <btstack/run_loop.h>
+#include "btstack/run_loop.h"
 
 #ifdef HAVE_TIME
 #include <sys/time.h>
@@ -58,11 +58,11 @@
 
 // internal use only
 typedef struct {
-	void (*init)(void);
-	void (*add_data_source)(data_source_t *dataSource);
-	int  (*remove_data_source)(data_source_t *dataSource);
-	void (*add_timer)(timer_source_t *timer);
-	int  (*remove_timer)(timer_source_t *timer); 
-	void (*execute)(void);
-	void (*dump_timer)(void);
+    void (*init)(void);
+    void (*add_data_source)(data_source_t *dataSource);
+    int  (*remove_data_source)(data_source_t *dataSource);
+    void (*add_timer)(timer_source_t *timer);
+    int  (*remove_timer)(timer_source_t *timer); 
+    void (*execute)(void);
+    void (*dump_timer)(void);
 } run_loop_t;
--- a/BTstack/sdp.c	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,662 +0,0 @@
-/*
- * Copyright (C) 2009-2012 by Matthias Ringwald
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- *    personal benefit and not for any commercial purpose or for
- *    monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at btstack@ringwald.ch
- *
- */
-
-/*
- * Implementation of the Service Discovery Protocol Server 
- */
-
-#include "sdp.h"
-
-
-#include <stdio.h>
-#include <string.h>
-
-#include <btstack/sdp_util.h>
-
-#include "hci_dump.h"
-#include "l2cap.h"
-
-#include "debug.h"
-
-// max reserved ServiceRecordHandle
-#define maxReservedServiceRecordHandle 0xffff
-
-// max SDP response
-#define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
-
-static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
-
-// registered service records
-static linked_list_t sdp_service_records = NULL;
-
-// our handles start after the reserved range
-static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2;
-
-static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
-
-static void (*app_packet_handler)(void * connection, uint8_t packet_type,
-                                  uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
-
-static uint16_t l2cap_cid = 0;
-static uint16_t sdp_response_size = 0;
-
-void sdp_init(){
-    // register with l2cap psm sevices - max MTU
-    l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff);
-}
-
-// register packet handler
-void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
-                                                 uint16_t channel, uint8_t *packet, uint16_t size)){
-	app_packet_handler = handler;
-    l2cap_cid = 0;
-}
-
-uint32_t sdp_get_service_record_handle(uint8_t * record){
-    uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
-    if (!serviceRecordHandleAttribute) return 0;
-    if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
-    if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
-    return READ_NET_32(serviceRecordHandleAttribute, 1); 
-}
-
-// data: event(8), len(8), status(8), service_record_handle(32)
-static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
-    if (!app_packet_handler) return;
-    uint8_t event[7];
-    event[0] = SDP_SERVICE_REGISTERED;
-    event[1] = sizeof(event) - 2;
-    event[2] = status;
-    bt_store_32(event, 3, handle);
-    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
-	(*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
-}
-
-service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
-    linked_item_t *it;
-    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
-        service_record_item_t * item = (service_record_item_t *) it;
-        if (item->service_record_handle == handle){
-            return item;
-        }
-    }
-    return NULL;
-}
-
-// get next free, unregistered service record handle
-uint32_t sdp_create_service_record_handle(void){
-    uint32_t handle = 0;
-    do {
-        handle = sdp_next_service_record_handle++;
-        if (sdp_get_record_for_handle(handle)) handle = 0;
-    } while (handle == 0);
-    return handle;
-}
-
-#ifdef EMBEDDED
-
-// register service record internally - this special version doesn't copy the record, it should not be freeed
-// pre: AttributeIDs are in ascending order
-// pre: ServiceRecordHandle is first attribute and valid
-// pre: record
-// @returns ServiceRecordHandle or 0 if registration failed
-uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){
-    // get user record handle
-    uint32_t record_handle = record_item->service_record_handle;
-    // get actual record
-    uint8_t *record = record_item->service_record;
-    
-    // check for ServiceRecordHandle attribute, returns pointer or null
-    uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
-    if (!req_record_handle) {
-        log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n");
-        return 0;
-    }
-    
-    // validate service record handle is not in reserved range
-    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
-    
-    // check if already in use
-    if (record_handle) {
-        if (sdp_get_record_for_handle(record_handle)) {
-            record_handle = 0;
-        }
-    }
-    
-    // create new handle if needed
-    if (!record_handle){
-        record_handle = sdp_create_service_record_handle();
-        // Write the handle back into the record too
-        record_item->service_record_handle = record_handle;
-        sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
-    }
-    
-    // add to linked list
-    linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
-    
-    sdp_emit_service_registered(connection, 0, record_item->service_record_handle);
-    
-    return record_handle;
-}
-
-#else
-
-// AttributeIDList used to remove ServiceRecordHandle
-static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
-
-// register service record internally - the normal version creates a copy of the record
-// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
-// @returns ServiceRecordHandle or 0 if registration failed
-uint32_t sdp_register_service_internal(void *connection, uint8_t * record){
-
-    // dump for now
-    // printf("Register service record\n");
-    // de_dump_data_element(record);
-    
-    // get user record handle
-    uint32_t record_handle = sdp_get_service_record_handle(record);
-
-    // validate service record handle is not in reserved range
-    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
-    
-    // check if already in use
-    if (record_handle) {
-        if (sdp_get_record_for_handle(record_handle)) {
-            record_handle = 0;
-        }
-    }
-    
-    // create new handle if needed
-    if (!record_handle){
-        record_handle = sdp_create_service_record_handle();
-    }
-    
-    // calculate size of new service record: DES (2 byte len) 
-    // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
-    uint16_t recordSize =  3 + (3 + 5) + de_get_data_size(record);
-        
-    // alloc memory for new service_record_item
-    service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
-    if (!newRecordItem) {
-        sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED);
-        return 0;
-    }
-    // link new service item to client connection
-    newRecordItem->connection = connection;
-    
-    // set new handle
-    newRecordItem->service_record_handle = record_handle;
-
-    // create updated service record
-    uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
-    
-    // create DES for new record
-    de_create_sequence(newRecord);
-    
-    // set service record handle
-    de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
-    de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
-    
-    // add other attributes
-    sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
-    
-    // dump for now
-    // de_dump_data_element(newRecord);
-    // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord));
-    
-    // add to linked list
-    linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
-    
-    sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle);
-
-    return record_handle;
-}
-
-#endif
-
-// unregister service record internally
-// 
-// makes sure one client cannot remove service records of other clients
-//
-void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){
-    service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
-    if (record_item && record_item->connection == connection) {
-        linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
-    }
-}
-
-// remove all service record for a client connection
-void sdp_unregister_services_for_connection(void *connection){
-    linked_item_t *it = (linked_item_t *) &sdp_service_records;
-    while (it->next){
-        service_record_item_t *record_item = (service_record_item_t *) it->next;
-        if (record_item->connection == connection){
-            it->next = it->next->next;
-#ifndef EMBEDDED
-            free(record_item);
-#endif
-        } else {
-            it = it->next;
-        }
-    }
-}
-
-// PDU
-// PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
-
-int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
-    sdp_response_buffer[0] = SDP_ErrorResponse;
-    net_store_16(sdp_response_buffer, 1, transaction_id);
-    net_store_16(sdp_response_buffer, 3, 2);
-    net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
-    return 7;
-}
-
-int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
-    
-    // get request details
-    uint16_t  transaction_id = READ_NET_16(packet, 1);
-    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
-    uint8_t * serviceSearchPattern = &packet[5];
-    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
-    uint16_t  maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
-    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
-    
-    // calc maxumumServiceRecordCount based on remote MTU
-    uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
-    
-    // continuation state contains index of next service record to examine
-    int      continuation = 0;
-    uint16_t continuation_index = 0;
-    if (continuationState[0] == 2){
-        continuation_index = READ_NET_16(continuationState, 1);
-    }
-    
-    // get and limit total count
-    linked_item_t *it;
-    uint16_t total_service_count   = 0;
-    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
-        service_record_item_t * item = (service_record_item_t *) it;
-        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
-        total_service_count++;
-    }
-    if (total_service_count > maximumServiceRecordCount){
-        total_service_count = maximumServiceRecordCount;
-    }
-    
-    // ServiceRecordHandleList at 9
-    uint16_t pos = 9;
-    uint16_t current_service_count  = 0;
-    uint16_t current_service_index  = 0;
-    uint16_t matching_service_count = 0;
-    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
-        service_record_item_t * item = (service_record_item_t *) it;
-
-        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
-        matching_service_count++;
-        
-        if (current_service_index < continuation_index) continue;
-
-        net_store_32(sdp_response_buffer, pos, item->service_record_handle);
-        pos += 4;
-        current_service_count++;
-        
-        if (matching_service_count >= total_service_count) break;
-
-        if (current_service_count >= maxNrServiceRecordsPerResponse){
-            continuation = 1;
-            continuation_index = current_service_index + 1;
-            break;
-        }
-    }
-    
-    // Store continuation state
-    if (continuation) {
-        sdp_response_buffer[pos++] = 2;
-        net_store_16(sdp_response_buffer, pos, continuation_index);
-        pos += 2;
-    } else {
-        sdp_response_buffer[pos++] = 0;
-    }
-
-    // header
-    sdp_response_buffer[0] = SDP_ServiceSearchResponse;
-    net_store_16(sdp_response_buffer, 1, transaction_id);
-    net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
-    net_store_16(sdp_response_buffer, 5, total_service_count);
-    net_store_16(sdp_response_buffer, 7, current_service_count);
-    
-    return pos;
-}
-
-int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
-    
-    // get request details
-    uint16_t  transaction_id = READ_NET_16(packet, 1);
-    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
-    uint32_t  serviceRecordHandle = READ_NET_32(packet, 5);
-    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 9);
-    uint8_t * attributeIDList = &packet[11];
-    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
-    uint8_t * continuationState = &packet[11+attributeIDListLen];
-    
-    // calc maximumAttributeByteCount based on remote MTU
-    uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
-    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
-        maximumAttributeByteCount = maximumAttributeByteCount2;
-    }
-    
-    // continuation state contains the offset into the complete response
-    uint16_t continuation_offset = 0;
-    if (continuationState[0] == 2){
-        continuation_offset = READ_NET_16(continuationState, 1);
-    }
-    
-    // get service record
-    service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
-    if (!item){
-        // service record handle doesn't exist
-        return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
-    }
-    
-    
-    // AttributeList - starts at offset 7
-    uint16_t pos = 7;
-    
-    if (continuation_offset == 0){
-        
-        // get size of this record
-        uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
-        
-        // store DES
-        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
-        maximumAttributeByteCount -= 3;
-        pos += 3;
-    }
-
-    // copy maximumAttributeByteCount from record
-    uint16_t bytes_used;
-    int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
-    pos += bytes_used;
-    
-    uint16_t attributeListByteCount = pos - 7;
-
-    if (complete) {
-        sdp_response_buffer[pos++] = 0;
-    } else {
-        continuation_offset += bytes_used;
-        sdp_response_buffer[pos++] = 2;
-        net_store_16(sdp_response_buffer, pos, continuation_offset);
-        pos += 2;
-    }
-
-    // header
-    sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
-    net_store_16(sdp_response_buffer, 1, transaction_id);
-    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
-    net_store_16(sdp_response_buffer, 5, attributeListByteCount); 
-    
-    return pos;
-}
-
-static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
-    uint16_t total_response_size = 0;
-    linked_item_t *it;
-    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
-        service_record_item_t * item = (service_record_item_t *) it;
-        
-        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
-        
-        // for all service records that match
-        total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
-    }
-    return total_response_size;
-}
-
-int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
-    
-    // SDP header before attribute sevice list: 7
-    // Continuation, worst case: 5
-    
-    // get request details
-    uint16_t  transaction_id = READ_NET_16(packet, 1);
-    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
-    uint8_t * serviceSearchPattern = &packet[5];
-    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
-    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
-    uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
-    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
-    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
-    
-    // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
-    uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
-    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
-        maximumAttributeByteCount = maximumAttributeByteCount2;
-    }
-    
-    // continuation state contains: index of next service record to examine
-    // continuation state contains: byte offset into this service record
-    uint16_t continuation_service_index = 0;
-    uint16_t continuation_offset = 0;
-    if (continuationState[0] == 4){
-        continuation_service_index = READ_NET_16(continuationState, 1);
-        continuation_offset = READ_NET_16(continuationState, 3);
-    }
-
-    // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount);
-    
-    // AttributeLists - starts at offset 7
-    uint16_t pos = 7;
-    
-    // add DES with total size for first request
-    if (continuation_service_index == 0 && continuation_offset == 0){
-        uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
-        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
-        // log_info("total response size %u\n", total_response_size);
-        pos += 3;
-        maximumAttributeByteCount -= 3;
-    }
-    
-    // create attribute list
-    int      first_answer = 1;
-    int      continuation = 0;
-    uint16_t current_service_index = 0;
-    linked_item_t *it = (linked_item_t *) sdp_service_records;
-    for ( ; it ; it = it->next, ++current_service_index){
-        service_record_item_t * item = (service_record_item_t *) it;
-        
-        if (current_service_index < continuation_service_index ) continue;
-        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
-
-        if (continuation_offset == 0){
-            
-            // get size of this record
-            uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
-            
-            // stop if complete record doesn't fits into response but we already have a partial response
-            if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
-                continuation = 1;
-                break;
-            }
-            
-            // store DES
-            de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
-            pos += 3;
-            maximumAttributeByteCount -= 3;
-        }
-        
-        first_answer = 0;
-    
-        // copy maximumAttributeByteCount from record
-        uint16_t bytes_used;
-        int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
-        pos += bytes_used;
-        maximumAttributeByteCount -= bytes_used;
-        
-        if (complete) {
-            continuation_offset = 0;
-            continue;
-        }
-        
-        continuation = 1;
-        continuation_offset += bytes_used;
-        break;
-    }
-    
-    uint16_t attributeListsByteCount = pos - 7;
-    
-    // Continuation State
-    if (continuation){
-        sdp_response_buffer[pos++] = 4;
-        net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
-        pos += 2;
-        net_store_16(sdp_response_buffer, pos, continuation_offset);
-        pos += 2;
-    } else {
-        // complete
-        sdp_response_buffer[pos++] = 0;
-    }
-        
-    // create SDP header
-    sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
-    net_store_16(sdp_response_buffer, 1, transaction_id);
-    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
-    net_store_16(sdp_response_buffer, 5, attributeListsByteCount);
-    
-    return pos;
-}
-
-static void sdp_try_respond(void){
-    if (!sdp_response_size ) return;
-    if (!l2cap_cid) return;
-    if (!l2cap_can_send_packet_now(l2cap_cid)) return;
-    
-    // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
-    uint16_t size = sdp_response_size;
-    sdp_response_size = 0;
-    l2cap_send_internal(l2cap_cid, sdp_response_buffer, size);
-}
-
-// we assume that we don't get two requests in a row
-static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-	uint16_t transaction_id;
-    SDP_PDU_ID_t pdu_id;
-    uint16_t remote_mtu;
-    // uint16_t param_len;
-    
-	switch (packet_type) {
-			
-		case L2CAP_DATA_PACKET:
-            pdu_id = (SDP_PDU_ID_t) packet[0];
-            transaction_id = READ_NET_16(packet, 1);
-            // param_len = READ_NET_16(packet, 3);
-            remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
-            // account for our buffer
-            if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
-                remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
-            }
-            
-            // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu);
-            switch (pdu_id){
-                    
-                case SDP_ServiceSearchRequest:
-                    sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
-                    break;
-                                        
-                case SDP_ServiceAttributeRequest:
-                    sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
-                    break;
-                    
-                case SDP_ServiceSearchAttributeRequest:
-                    sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
-                    break;
-                    
-                default:
-                    sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
-                    break;
-            }
-            
-            sdp_try_respond();
-            
-			break;
-			
-		case HCI_EVENT_PACKET:
-			
-			switch (packet[0]) {
-
-				case L2CAP_EVENT_INCOMING_CONNECTION:
-                    if (l2cap_cid) {
-                        // CONNECTION REJECTED DUE TO LIMITED RESOURCES 
-                        l2cap_decline_connection_internal(channel, 0x0d);
-                        break;
-                    }
-                    // accept
-                    l2cap_cid = channel;
-                    sdp_response_size = 0;
-                    l2cap_accept_connection_internal(channel);
-					break;
-                    
-                case L2CAP_EVENT_CHANNEL_OPENED:
-                    if (packet[2]) {
-                        // open failed -> reset
-                        l2cap_cid = 0;
-                    }
-                    break;
-
-                case L2CAP_EVENT_CREDITS:
-                case DAEMON_EVENT_HCI_PACKET_SENT:
-                    sdp_try_respond();
-                    break;
-                
-                case L2CAP_EVENT_CHANNEL_CLOSED:
-                    if (channel == l2cap_cid){
-                        // reset
-                        l2cap_cid = 0;
-                    }
-                    break;
-					                    
-				default:
-					// other event
-					break;
-			}
-			break;
-			
-		default:
-			// other packet type
-			break;
-	}
-}
-
--- a/BTstack/sdp.h	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2009-2012 by Matthias Ringwald
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- *    personal benefit and not for any commercial purpose or for
- *    monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at btstack@ringwald.ch
- *
- */
-#pragma once
-
-#include <stdint.h>
-#include <btstack/linked_list.h>
-
-#include "config.h"
-
-typedef enum {
-	SDP_ErrorResponse = 1,
-	SDP_ServiceSearchRequest,
-	SDP_ServiceSearchResponse,
-	SDP_ServiceAttributeRequest,
-	SDP_ServiceAttributeResponse,
-	SDP_ServiceSearchAttributeRequest,
-	SDP_ServiceSearchAttributeResponse
-} SDP_PDU_ID_t;
-
-// service record
-// -- uses user_data field for actual
-typedef struct {
-    // linked list - assert: first field
-    linked_item_t   item;
-    
-    // client connection
-    void *  connection;
-    
-    // data is contained in same memory
-    uint32_t        service_record_handle;
-    uint8_t         service_record[0];
-} service_record_item_t;
-
-
-void sdp_init(void);
-
-void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
-                                                 uint16_t channel, uint8_t *packet, uint16_t size));
-
-#ifdef EMBEDDED
-// register service record internally - the normal version creates a copy of the record
-// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
-// @returns ServiceRecordHandle or 0 if registration failed
-uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item);
-#else
-// register service record internally - this special version doesn't copy the record, it cannot be freeed
-// pre: AttributeIDs are in ascending order
-// pre: ServiceRecordHandle is first attribute and valid
-// pre: record
-// @returns ServiceRecordHandle or 0 if registration failed
-uint32_t sdp_register_service_internal(void *connection, uint8_t * service_record);
-#endif
-
-// unregister service record internally
-void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle);
-
-//
-void sdp_unregister_services_for_connection(void *connection);
-
-//
-int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu);
-int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu);
-int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu);
--- a/BTstack/sdp_util.c	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,698 +0,0 @@
-/*
- * Copyright (C) 2009-2012 by Matthias Ringwald
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- *    personal benefit and not for any commercial purpose or for
- *    monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at btstack@ringwald.ch
- *
- */
-
-/*
- *  sdp_util.c
- */
-
-#include <btstack/sdp_util.h>
-#include <btstack/utils.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <inttypes.h>   // PRIx32
-
-// workaround for missing PRIx32 on mspgcc (16-bit MCU)
-#ifndef PRIx32
-#warning Using own: #define PRIx32 "lx"
-#define PRIx32 "lx"
-#endif
-
-// date element type names
-const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"};
-
-// Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
-const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
-    0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
-
-void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){
-    memcpy(uuid, sdp_bluetooth_base_uuid, 16);
-    net_store_32(uuid, 0, shortUUID);
-}
-
-// MARK: DataElement getter
-de_size_t de_get_size_type(uint8_t *header){
-    return (de_size_t) (header[0] & 7);
-}
-
-de_type_t de_get_element_type(uint8_t *header){
-    return (de_type_t) (header[0] >> 3);
-}
-
-int de_get_header_size(uint8_t * header){
-    de_size_t de_size = de_get_size_type(header);
-    if (de_size <= DE_SIZE_128) {
-        return 1;
-    }
-    return 1 + (1 << (de_size-DE_SIZE_VAR_8));
-}
-
-int de_get_data_size(uint8_t * header){
-    uint32_t result = 0;
-    de_type_t de_type = de_get_element_type(header);
-    de_size_t de_size = de_get_size_type(header);
-    switch (de_size){
-        case DE_SIZE_VAR_8:
-            result = header[1];
-            break;
-        case DE_SIZE_VAR_16:
-            result = READ_NET_16(header,1);
-            break;
-        case DE_SIZE_VAR_32:
-            result = READ_NET_32(header,1);
-            break;
-        default:
-        // case DE_SIZE_8:
-        // case DE_SIZE_16:
-        // case DE_SIZE_32:
-        // case DE_SIZE_64:
-        // case DE_SIZE_128:
-            if (de_type == DE_NIL) return 0;
-            return 1 << de_size;
-    }
-    return result;    
-}
-
-int de_get_len(uint8_t *header){
-    return de_get_header_size(header) + de_get_data_size(header); 
-}
-
-// @returns: element is valid UUID
-int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
-    de_type_t uuidType = de_get_element_type(element);
-    de_size_t uuidSize = de_get_size_type(element);
-    if (uuidType != DE_UUID) return 0;
-    uint32_t shortUUID;
-    switch (uuidSize){
-        case DE_SIZE_16:
-            shortUUID = READ_NET_16(element, 1);
-            break;
-        case DE_SIZE_32:
-            shortUUID = READ_NET_32(element, 1);
-            break;
-        case DE_SIZE_128:
-            memcpy(uuid128, element+1, 16);
-            return 1;
-        default:
-            return 0;
-    }
-    sdp_normalize_uuid(uuid128, shortUUID);
-    return 1;
-}
-
-// functions to create record
-static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){
-    header[0] = (type << 3) | size; 
-}
-
-void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){
-    header[0] = (type << 3) | size; 
-    switch (size){
-        case DE_SIZE_VAR_8:
-            header[1] = len;
-            break;
-        case DE_SIZE_VAR_16:
-            net_store_16(header, 1, len);
-            break;
-        case DE_SIZE_VAR_32:
-            net_store_32(header, 1, len);
-            break;
-        default:
-            break;
-    }
-}
-
-// MARK: DataElement creation
-
-/* starts a new sequence in empty buffer - first call */
-void de_create_sequence(uint8_t *header){
-    de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
-};
-
-/* starts a sub-sequence, @returns handle for sub-sequence */
-uint8_t * de_push_sequence(uint8_t *header){
-    int element_len = de_get_len(header);
-    de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
-    return header + element_len;
-}
-
-/* closes the current sequence and updates the parent sequence */
-void de_pop_sequence(uint8_t * parent, uint8_t * child){
-    int child_len = de_get_len(child);
-    int data_size_parent = READ_NET_16(parent,1);
-    net_store_16(parent, 1, data_size_parent + child_len);
-}
-
-/* adds a single number value and 16+32 bit UUID to the sequence */
-void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){
-    int data_size   = READ_NET_16(seq,1);
-    int element_size = 1;   // e.g. for DE_TYPE_NIL
-    de_store_descriptor(seq+3+data_size, type, size); 
-    switch (size){
-        case DE_SIZE_8:
-            if (type != DE_NIL){
-                seq[4+data_size] = value;
-                element_size = 2;
-            }
-            break;
-        case DE_SIZE_16:
-            net_store_16(seq, 4+data_size, value);
-            element_size = 3;
-            break;
-        case DE_SIZE_32:
-            net_store_32(seq, 4+data_size, value);
-            element_size = 5;
-            break;
-        default:
-            break;
-    }
-    net_store_16(seq, 1, data_size+element_size);
-}
-
-/* add a single block of data, e.g. as DE_STRING, DE_URL */
-void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){
-    int data_size   = READ_NET_16(seq,1);
-    if (size > 0xff) {
-        // use 16-bit lengh information (3 byte header)
-        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); 
-        data_size += 3;
-    } else {
-        // use 8-bit lengh information (2 byte header)
-        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); 
-        data_size += 2;
-    }
-    memcpy( seq + 3 + data_size, data, size);
-    data_size += size;
-    net_store_16(seq, 1, data_size);
-}
-
-void de_add_uuid128(uint8_t * seq, uint8_t * uuid){
-    int data_size   = READ_NET_16(seq,1);
-    de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); 
-    memcpy( seq + 4 + data_size, uuid, 16);
-    net_store_16(seq, 1, data_size+1+16);
-}
-
-void sdp_add_attribute(uint8_t *seq, uint16_t attributeID, uint8_t attributeValue){
-}
-
-// MARK: DataElementSequence traversal
-typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context);
-static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){
-    de_type_t type = de_get_element_type(element);
-    if (type != DE_DES) return;
-    int pos = de_get_header_size(element);
-    int end_pos = de_get_len(element);
-    while (pos < end_pos){
-        de_type_t elemType = de_get_element_type(element + pos);
-        de_size_t elemSize = de_get_size_type(element + pos);
-        uint8_t done = (*handler)(element + pos, elemType, elemSize, context); 
-        if (done) break;
-        pos += de_get_len(element + pos);
-    }
-}
-
-// MARK: AttributeList traversal
-typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context);
-static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){
-    de_type_t type = de_get_element_type(element);
-    if (type != DE_DES) return;
-    int pos = de_get_header_size(element);
-    int end_pos = de_get_len(element);
-    while (pos < end_pos){
-        de_type_t idType = de_get_element_type(element + pos);
-        de_size_t idSize = de_get_size_type(element + pos);
-        if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type
-        uint16_t attribute_id = READ_NET_16(element, pos + 1);
-        pos += 3;
-        if (pos >= end_pos) break; // array out of bounds
-        de_type_t valueType = de_get_element_type(element + pos);
-        de_size_t valueSize = de_get_size_type(element + pos);
-        uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); 
-        if (done) break;
-        pos += de_get_len(element + pos);
-    }
-}
-
-// MARK: AttributeID in AttributeIDList 
-// attribute ID in AttributeIDList
-// context { result, attributeID }
-struct sdp_context_attributeID_search {
-    int result;
-    uint16_t attributeID;
-};
-static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
-    struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context;
-    if (type != DE_UINT) return 0;
-    switch (size) {
-        case DE_SIZE_16:
-            if (READ_NET_16(element, 1) == context->attributeID) {
-                context->result = 1;
-                return 1;
-            }
-            break;
-        case DE_SIZE_32:
-            if (READ_NET_16(element, 1) <= context->attributeID
-            &&  context->attributeID <= READ_NET_16(element, 3)) {
-                context->result = 1;
-                return 1;
-            }
-            break;
-        default:
-            break;
-    }
-    return 0;
-}
-int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){
-    struct sdp_context_attributeID_search attributeID_search;
-    attributeID_search.result = 0;
-    attributeID_search.attributeID = attributeID;
-    de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search);
-    return attributeID_search.result;
-}
-
-// MARK: Append Attributes for AttributeIDList
-// pre: buffer contains DES with 2 byte length field
-struct sdp_context_append_attributes {
-    uint8_t * buffer;
-    uint16_t startOffset;     // offset of when to start copying
-    uint16_t maxBytes;
-    uint16_t usedBytes;
-    uint8_t *attributeIDList;
-};
-
-static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
-    struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context;
-    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
-        // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute)
-        uint16_t data_size = READ_NET_16(context->buffer, 1);
-        int attribute_len = de_get_len(attributeValue);
-        if (3 + data_size + (3 + attribute_len) <= context->maxBytes) {
-            // copy Attribute
-            de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID);   
-            data_size += 3; // 3 bytes
-            memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len);
-            net_store_16(context->buffer,1,data_size+attribute_len);
-        } else {
-            // not enought space left -> continue with previous element
-            return 1;
-        }
-    }
-    return 0;
-}
-
-// maxBytes: maximal size of data element sequence
-uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){
-    struct sdp_context_append_attributes context;
-    context.buffer = buffer;
-    context.maxBytes = maxBytes;
-    context.usedBytes = 0;
-    context.startOffset = startOffset;
-    context.attributeIDList = attributeIDList;
-    sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context);
-    return context.usedBytes;
-}
-
-// MARK: Filter attributes that match attribute list from startOffset and a max nr bytes
-struct sdp_context_filter_attributes {
-    uint8_t * buffer;
-    uint16_t startOffset;     // offset of when to start copying
-    uint16_t maxBytes;
-    uint16_t usedBytes;
-    uint8_t *attributeIDList;
-    int      complete;
-};
-
-// copy data with given start offset and max bytes, returns OK if all data has been copied
-static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){
-    int ok = 1;
-    uint16_t remainder_len = len - context->startOffset;
-    if (context->maxBytes < remainder_len){
-        remainder_len = context->maxBytes;
-        ok = 0;
-    }
-    memcpy(context->buffer, &data[context->startOffset], remainder_len);
-    context->usedBytes += remainder_len;
-    context->buffer    += remainder_len;
-    context->maxBytes  -= remainder_len;
-    context->startOffset = 0;
-    return ok;
-}
-
-static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
-    struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context;
-
-    if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0;
-
-    // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)}
-
-    // handle Attribute ID
-    if (context->startOffset >= 3){
-        context->startOffset -= 3;
-    } else {
-        uint8_t idBuffer[3];
-        de_store_descriptor(idBuffer, DE_UINT,  DE_SIZE_16);
-        net_store_16(idBuffer,1,attributeID);
-        
-        int ok = spd_append_range(context, 3, idBuffer);
-        if (!ok) {
-            context->complete = 0;
-            return 1;
-        }
-    }
-    
-    // handle Attribute Value
-    int attribute_len = de_get_len(attributeValue);
-    if (context->startOffset >= attribute_len) {
-        context->startOffset -= attribute_len;
-        return 0;
-    }
-    
-    int ok = spd_append_range(context, attribute_len, attributeValue);
-    if (!ok) {
-        context->complete = 0;
-        return 1;
-    }
-    return 0;
-}
-
-int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){
-
-    struct sdp_context_filter_attributes context;
-    context.buffer = buffer;
-    context.maxBytes = maxBytes;
-    context.usedBytes = 0;
-    context.startOffset = startOffset;
-    context.attributeIDList = attributeIDList;
-    context.complete = 1;
-
-    sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context);
-
-    *usedBytes = context.usedBytes;
-    return context.complete;
-}
-
-// MARK: Get sum of attributes matching attribute list
-struct sdp_context_get_filtered_size {
-    uint8_t *attributeIDList;
-    uint16_t size;
-};
-
-static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
-    struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context;
-    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
-        context->size += 3 + de_get_len(attributeValue);
-    }
-    return 0;
-}
-
-int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){
-    struct sdp_context_get_filtered_size context;
-    context.size = 0;
-    context.attributeIDList = attributeIDList;
-    sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context);
-    return context.size;
-}
-
-// MARK: Get AttributeValue for AttributeID
-// find attribute (ELEMENT) by ID
-struct sdp_context_attribute_by_id {
-    uint16_t  attributeID;
-    uint8_t * attributeValue;
-};
-static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
-    struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context;
-    if (attributeID == context->attributeID) {
-        context->attributeValue = attributeValue;
-        return 1;
-    }
-    return 0;
-}
-
-uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){
-    struct sdp_context_attribute_by_id context;
-    context.attributeValue = NULL;
-    context.attributeID = attributeID;
-    sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context);
-    return context.attributeValue;
-}
-
-// MARK: Set AttributeValue for AttributeID
-struct sdp_context_set_attribute_for_id {
-    uint16_t  attributeID;
-    uint32_t  attributeValue;
-    uint8_t   attributeFound;
-};
-static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
-    struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context;
-    if (attributeID == context->attributeID) {
-        context->attributeFound = 1;
-        switch (size){
-            case DE_SIZE_8:
-                if (attributeType != DE_NIL){
-                    attributeValue[1] = context->attributeValue;
-                }
-                break;
-            case DE_SIZE_16:
-                net_store_16(attributeValue, 1, context->attributeValue);
-                break;
-            case DE_SIZE_32:
-                net_store_32(attributeValue, 1, context->attributeValue);
-                break;
-                // Might want to support STRINGS to, copy upto original length
-            default:
-                break;
-        }        
-        return 1;
-    }
-    return 0;
-}
-uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){
-    struct sdp_context_set_attribute_for_id context;
-    context.attributeID = attributeID;
-    context.attributeValue = value;
-    context.attributeFound = 0;
-    sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context);
-    return context.attributeFound;
-}
-
-// MARK: ServiceRecord contains UUID
-// service record contains UUID
-// context { normalizedUUID }
-struct sdp_context_contains_uuid128 {
-    uint8_t * uuid128;
-    int result;
-};
-int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128);
-static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
-    struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context;
-    uint8_t normalizedUUID[16];
-    if (type == DE_UUID){
-        uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
-        context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0;
-    }
-    if (type == DE_DES){
-        context->result = sdp_record_contains_UUID128(element, context->uuid128);
-    }
-    return context->result;
-}
-int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){
-    struct sdp_context_contains_uuid128 context;
-    context.uuid128 = uuid128;
-    context.result = 0;
-    de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context);
-    return context.result;
-}
-    
-// MARK: ServiceRecord matches SearchServicePattern
-// if UUID in searchServicePattern is not found in record => false
-// context { result, record }
-struct sdp_context_match_pattern {
-    uint8_t * record;
-    int result;
-};
-int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){
-    struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context;
-    uint8_t normalizedUUID[16];
-    uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
-    if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){
-        context->result = 0;
-        return 1;
-    }
-    return 0;
-}
-int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){
-    struct sdp_context_match_pattern context;
-    context.record = record;
-    context.result = 1;
-    de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context);
-    return context.result;
-}
-
-// MARK: Dump DataElement
-// context { indent }
-static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){
-    int indent = *(int*) my_context;
-    int i;
-    for (i=0; i<indent;i++) printf("    ");
-    int pos     = de_get_header_size(element);
-    int end_pos = de_get_len(element);
-    printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos);
-    if (de_type == DE_DES) {
-		printf("\n");
-        indent++;
-        de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent);
-    } else if (de_type == DE_UUID && de_size == DE_SIZE_128) {
-        printf(", value: ");
-        printUUID(element+1);
-        printf("\n");
-    } else if (de_type == DE_STRING) {
-        int len = 0;
-        switch (de_size){
-            case DE_SIZE_VAR_8:
-                len = element[1];
-                break;
-            case DE_SIZE_VAR_16:
-                len = READ_NET_16(element, 1);
-                break;
-            default:
-                break;
-        }
-        printf("len %u (0x%02x)\n", len, len);
-        hexdump(&element[pos], len);
-    } else {
-        uint32_t value = 0;
-        switch (de_size) {
-            case DE_SIZE_8:
-                if (de_type != DE_NIL){
-                    value = element[pos];
-                }
-                break;
-            case DE_SIZE_16:
-				value = READ_NET_16(element,pos);
-                break;
-            case DE_SIZE_32:
-				value = READ_NET_32(element,pos);
-                break;
-            default:
-                break;
-        }
-        printf(", value: 0x%08" PRIx32 "\n", value);
-    }
-    return 0;
-}
-
-void de_dump_data_element(uint8_t * record){
-    int indent = 0;
-    // hack to get root DES, too.
-    de_type_t type = de_get_element_type(record);
-    de_size_t size = de_get_size_type(record);
-    de_traversal_dump_data(record, type, size, (void*) &indent);
-}
-
-void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){
-	
-	uint8_t* attribute;
-	de_create_sequence(service);
-    
-    // 0x0000 "Service Record Handle"
-	de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
-	de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
-    
-	// 0x0001 "Service Class ID List"
-	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
-	attribute = de_push_sequence(service);
-	{
-		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1101 );
-	}
-	de_pop_sequence(service, attribute);
-	
-	// 0x0004 "Protocol Descriptor List"
-	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
-	attribute = de_push_sequence(service);
-	{
-		uint8_t* l2cpProtocol = de_push_sequence(attribute);
-		{
-			de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, 0x0100);
-		}
-		de_pop_sequence(attribute, l2cpProtocol);
-		
-		uint8_t* rfcomm = de_push_sequence(attribute);
-		{
-			de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, 0x0003);  // rfcomm_service
-			de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  service_id);  // rfcomm channel
-		}
-		de_pop_sequence(attribute, rfcomm);
-	}
-	de_pop_sequence(service, attribute);
-	
-	// 0x0005 "Public Browse Group"
-	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
-	attribute = de_push_sequence(service);
-	{
-		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1002 );
-	}
-	de_pop_sequence(service, attribute);
-	
-	// 0x0006
-	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList);
-	attribute = de_push_sequence(service);
-	{
-		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
-		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
-		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
-	}
-	de_pop_sequence(service, attribute);
-	
-	// 0x0009 "Bluetooth Profile Descriptor List"
-	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
-	attribute = de_push_sequence(service);
-	{
-		uint8_t *sppProfile = de_push_sequence(attribute);
-		{
-			de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, 0x1101);
-			de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0100);
-		}
-		de_pop_sequence(attribute, sppProfile);
-	}
-	de_pop_sequence(service, attribute);
-	
-	// 0x0100 "ServiceName"
-	de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
-	de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
-}
--- a/led_counter.cpp	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-#if 0
-//*****************************************************************************
-//
-// led_counter demo - uses the BTstack run loop to blink an LED
-//
-//*****************************************************************************
-#include "mbed.h"
-#include <btstack/run_loop.h>
-
-Serial pc(USBTX, USBRX);
-DigitalOut led1(LED1), led2(LED2);
-
-#define HEARTBEAT_PERIOD_MS 1000
-
-static void  heartbeat_handler(struct timer *ts){
-
-    // increment counter
-    static int counter = 0;
-    char lineBuffer[30];
-    sprintf(lineBuffer, "BTstack counter %04u\n\r", ++counter);
-    printf(lineBuffer);
-    
-    // toggle LED
-    led2 = !led2;
-    
-    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(ts);
-} 
-
-// main
-int main(void)
-{
-    pc.baud(921600);
-    printf("%s\n", __FILE__);
-
-    // init LEDs
-    led1 = led2 = 1;
-    
-    /// GET STARTED with BTstack ///
-    run_loop_init(RUN_LOOP_EMBEDDED);
-        
-    // set one-shot timer
-    timer_source_t heartbeat;
-    heartbeat.process = &heartbeat_handler;
-    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(&heartbeat);
-    
-    printf("Run...\n\r");
-
-    // go!
-    run_loop_execute();    
-    
-    // happy compiler!
-    return 0;
-}
-#endif
\ No newline at end of file
--- a/mouse_demo.cpp	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-#if 0
-/* mouse_demo.cpp */
-#include "mbed.h"
-#include <btstack/run_loop.h>
-#include <btstack/hci_cmds.h>
-#include "hci.h"
-#include "l2cap.h"
-#include "debug.h"
-#include "bd_addr.h"  // class bd_addr
-Serial pc(USBTX, USBRX);
-DigitalOut led1(LED1), led2(LED2), led3(LED3);
-
-#define INQUIRY_INTERVAL 15
-
-bd_addr addr;
-
-static void hid_process_packet(uint8_t* report, int size)
-{
-    if (report[0] == 0xa1 && report[1] == 0x02) {
-        led1 = report[2] & 0x01; // left
-        led2 = report[2] & 0x02; // right
-        led3 = report[2] & 0x04; // center
-    }
-    hexdump(report, size);
-}
-
-static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    
-    if (packet_type == HCI_EVENT_PACKET && packet[0] == L2CAP_EVENT_CHANNEL_OPENED){
-        if (packet[2]) {
-            log_info("Connection failed\n");
-            return;
-        }
-        log_info("Connected\n");
-    }
-    if (packet_type == L2CAP_DATA_PACKET){
-        // handle input
-        log_info("HID report, size %u\n", size);
-        hid_process_packet(packet, size);
-    }
-}
-
-static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    if (packet_type == HCI_EVENT_PACKET) {
-        switch (packet[0]) {
-            case BTSTACK_EVENT_STATE:
-                // bt stack activated, get started - set local name
-                if (packet[2] == HCI_STATE_WORKING) {
-                    hci_send_cmd(&hci_write_authentication_enable, 1);
-                }
-                break;
-                    
-            case HCI_EVENT_INQUIRY_RESULT:
-                // ignore none mouses
-                if ((packet[12] & 0x80) != 0x80 || packet[13] != 0x25) break;
-                addr.data(&packet[3]);
-                log_info("Mouse addr: %s\n", addr.to_str());
-                hci_send_cmd(&hci_inquiry_cancel);
-                break;
-                    
-            case HCI_EVENT_INQUIRY_COMPLETE:
-                log_info("No mouse found :(\n");
-                break;
-                
-            case HCI_EVENT_LINK_KEY_REQUEST:
-                // deny link key request
-                hci_send_cmd(&hci_link_key_request_negative_reply, addr.data());
-                break;
-                    
-            case HCI_EVENT_PIN_CODE_REQUEST:
-                // inform about pin code request
-                log_info("Enter 0000\n");
-                hci_send_cmd(&hci_pin_code_request_reply, addr.data(), 4, "0000");
-                break;
-                    
-            case HCI_EVENT_COMMAND_COMPLETE:
-                if (COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable)){
-                    log_info("Inquiry\n");
-                    hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
-                }
-                if (COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel) ) {
-                    // inq successfully cancelled
-                    log_info("Connecting\n");
-                    l2cap_create_channel_internal(NULL, l2cap_packet_handler, addr.data(), PSM_HID_INTERRUPT, 150);
-                }
-                break;
-        }
-    }
-}
-
-int main(void){
-    pc.baud(921600);
-    log_info("%s\n", __FILE__);
-
-    // init LEDs
-    led1 = led2 = led3 = 1;
-    
-    // GET STARTED
-    run_loop_init(RUN_LOOP_EMBEDDED);
-
-    // init HCI
-    hci_transport_t* transport = hci_transport_usb_instance();
-    remote_device_db_t* remote_db = (remote_device_db_t *)&remote_device_db_memory;
-    hci_init(transport, NULL, NULL, remote_db);
-
-    // init L2CAP
-    l2cap_init();
-    l2cap_register_packet_handler(packet_handler);
-
-    // turn on!, send RESET command
-    hci_power_control(HCI_POWER_ON);
-            
-    // go!
-    run_loop_execute();    
-    
-    return 0;
-}
-#endif
\ No newline at end of file
--- a/spp_counter.cpp	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-#if 0
-//*****************************************************************************
-//
-// spp_counter demo - it provides a SPP and sends a counter every second
-//
-// it doesn't use the LCD to get down to a minimal memory footpring
-//
-//*****************************************************************************
-#include "mbed.h"
-#include <btstack/hci_cmds.h>
-#include <btstack/run_loop.h>
-#include <btstack/sdp_util.h>
-
-#include "hci.h"
-#include "l2cap.h"
-#include "btstack_memory.h"
-#include "remote_device_db.h"
-#include "rfcomm.h"
-#include "sdp.h"
-#include "config.h"
-#include "debug.h"
-#include "bd_addr.h"  // class bd_addr
-
-Serial pc(USBTX, USBRX);
-DigitalOut led1(LED1), led2(LED2);
-
-#define HEARTBEAT_PERIOD_MS 1000
-
-static uint8_t   rfcomm_channel_nr = 1;
-static uint16_t  rfcomm_channel_id = 0;
-static uint8_t   spp_service_buffer[128];
-
-// Bluetooth logic
-static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    bd_addr_t event_addr;
-    uint8_t   rfcomm_channel_nr;
-    uint16_t  mtu;
-    
-    switch (packet_type) {
-        case HCI_EVENT_PACKET:
-            switch (packet[0]) {
-                    
-                case BTSTACK_EVENT_STATE:
-                    // bt stack activated, get started - set local name
-                    if (packet[2] == HCI_STATE_WORKING) {
-                        hci_send_cmd(&hci_write_local_name, "mbed-Demo");
-                    }
-                    break;
-                
-                case HCI_EVENT_COMMAND_COMPLETE:
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
-                        bt_flip_addr(event_addr, &packet[6]);
-                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
-                        break;
-                    }
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
-                        hci_discoverable_control(1);
-                        break;
-                    }
-                    break;
-
-                case HCI_EVENT_LINK_KEY_REQUEST:
-                    // deny link key request
-                    log_info("Link key request\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
-                    break;
-                    
-                case HCI_EVENT_PIN_CODE_REQUEST:
-                    // inform about pin code request
-                    log_info("Pin code request - using '0000'\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
-                    break;
-                
-                case RFCOMM_EVENT_INCOMING_CONNECTION:
-                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
-                    bt_flip_addr(event_addr, &packet[2]); 
-                    rfcomm_channel_nr = packet[8];
-                    rfcomm_channel_id = READ_BT_16(packet, 9);
-                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
-                    rfcomm_accept_connection_internal(rfcomm_channel_id);
-                    break;
-                    
-                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
-                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
-                    if (packet[2]) {
-                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
-                    } else {
-                        rfcomm_channel_id = READ_BT_16(packet, 12);
-                        mtu = READ_BT_16(packet, 14);
-                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
-                    }
-                    break;
-                    
-                case RFCOMM_EVENT_CHANNEL_CLOSED:
-                    rfcomm_channel_id = 0;
-                    break;
-                
-                default:
-                    break;
-            }
-            break;
-                        
-        default:
-            break;
-    }
-}
-
-static void  heartbeat_handler(struct timer *ts){
-
-    if (rfcomm_channel_id){
-        static int counter = 0;
-        char lineBuffer[32];
-        snprintf(lineBuffer, sizeof(lineBuffer), "counter %04u\n\r", ++counter);
-        log_info("%s\n", lineBuffer);
-        int err = rfcomm_send_internal(rfcomm_channel_id, (uint8_t*) lineBuffer, strlen(lineBuffer));
-        if (err) {
-            log_info("rfcomm_send_internal -> error %d", err);
-        }
-    }
-    
-    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(ts);
-    led2 = !led2;
-} 
-
-// main
-int main(void)
-{
-    pc.baud(921600);
-    log_info("%s\n", __FILE__);
-
-
-    // init LEDs
-    led1 = led2 = 1;
-    
-    /// GET STARTED with BTstack ///
-    btstack_memory_init();
-    run_loop_init(RUN_LOOP_EMBEDDED);
-    
-    // init HCI
-    hci_transport_t    * transport = hci_transport_usb_instance();
-    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
-    hci_init(transport, NULL, NULL, remote_db);
-    
-    // init L2CAP
-    l2cap_init();
-    l2cap_register_packet_handler(packet_handler);
-    
-    // init RFCOMM
-    rfcomm_init();
-    rfcomm_register_packet_handler(packet_handler);
-    rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100);  // reserved channel, mtu=100
-
-    // init SDP, create record for SPP and register with SDP
-    sdp_init();
-    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
-    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
-    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
-    log_info("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
-    sdp_register_service_internal(NULL, service_record_item);
-    
-    // set one-shot timer
-    timer_source_t heartbeat;
-    heartbeat.process = &heartbeat_handler;
-    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(&heartbeat);
-    
-    log_info("Run...\n\r");
-
-     // turn on!
-    hci_power_control(HCI_POWER_ON);
-
-    // go!
-    run_loop_execute();    
-    
-    // happy compiler!
-    return 0;
-}
-
-#endif
\ No newline at end of file
--- a/spp_demo.cpp	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-#if 1
-/*
- * spp_demo
- */
-#include "mbed.h"
-#include <btstack/hci_cmds.h>
-#include <btstack/run_loop.h>
-#include <btstack/sdp_util.h>
-#include "hci.h"
-#include "l2cap.h"
-#include "btstack_memory.h"
-#include "remote_device_db.h"
-#include "rfcomm.h"
-#include "sdp.h"
-#include "config.h"
-#include "debug.h"
-#include "bd_addr.h"  // class bd_addr
-
-Serial pc(USBTX, USBRX);
-DigitalOut led1(LED1), led2(LED2), led3(LED3);
-
-#define HEARTBEAT_PERIOD_MS 500
-
-static uint8_t   rfcomm_channel_nr = 1;
-static uint16_t  rfcomm_channel_id = 0;
-static uint8_t   spp_service_buffer[128];
-
-// Bluetooth logic
-static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    bd_addr_t event_addr;
-    uint8_t   rfcomm_channel_nr;
-    uint16_t  mtu;
-    int err;
-    switch (packet_type) {
-        case HCI_EVENT_PACKET:
-            switch (packet[0]) {
-                    
-                case BTSTACK_EVENT_STATE:
-                    // bt stack activated, get started - set local name
-                    if (packet[2] == HCI_STATE_WORKING) {
-                        hci_send_cmd(&hci_write_local_name, "mbed");
-                    }
-                    break;
-                
-                case HCI_EVENT_COMMAND_COMPLETE:
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
-                        bt_flip_addr(event_addr, &packet[6]);
-                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
-                        break;
-                    }
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
-                        hci_discoverable_control(1);
-                        break;
-                    }
-                    break;
-
-                case HCI_EVENT_LINK_KEY_REQUEST:
-                    // deny link key request
-                    log_info("Link key request\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
-                    break;
-                    
-                case HCI_EVENT_PIN_CODE_REQUEST:
-                    // inform about pin code request
-                    log_info("Pin code request - using '0000'\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
-                    break;
-                
-                case RFCOMM_EVENT_INCOMING_CONNECTION:
-                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
-                    bt_flip_addr(event_addr, &packet[2]); 
-                    rfcomm_channel_nr = packet[8];
-                    rfcomm_channel_id = READ_BT_16(packet, 9);
-                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
-                    rfcomm_accept_connection_internal(rfcomm_channel_id);
-                    break;
-                    
-                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
-                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
-                    if (packet[2]) {
-                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
-                    } else {
-                        rfcomm_channel_id = READ_BT_16(packet, 12);
-                        mtu = READ_BT_16(packet, 14);
-                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
-                    }
-                    break;
-                    
-                case RFCOMM_EVENT_CHANNEL_CLOSED:
-                    rfcomm_channel_id = 0;
-                    break;
-                
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_DATA_PACKET:
-            // loopback
-            if (rfcomm_channel_id) {
-                err = rfcomm_send_internal(rfcomm_channel_id, packet, size);
-                if (err) {
-                    log_info("rfcomm_send_internal -> error %d", err);
-                }
-            }
-            led3 = !led3;
-            break;
-        default:
-            break;
-    }
-}
-
-static void  heartbeat_handler(struct timer *ts){
-    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(ts);
-    led2 = !led2;
-} 
-
-// main
-int main(void)
-{
-    pc.baud(921600);
-    log_info("%s\n", __FILE__);
-
-    // init LEDs
-    led1 = led2 = led3 = 1;
-    
-    /// GET STARTED with BTstack ///
-    btstack_memory_init();
-    run_loop_init(RUN_LOOP_EMBEDDED);
-    
-    // init HCI
-    hci_transport_t* transport = hci_transport_usb_instance();
-    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
-    hci_init(transport, NULL, NULL, remote_db);
-    
-    // init L2CAP
-    l2cap_init();
-    l2cap_register_packet_handler(packet_handler);
-    
-    // init RFCOMM
-    rfcomm_init();
-    rfcomm_register_packet_handler(packet_handler);
-    rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100);  // reserved channel, mtu=100
-
-    // init SDP, create record for SPP and register with SDP
-    sdp_init();
-    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
-    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
-    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "loopback");
-    log_info("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
-    sdp_register_service_internal(NULL, service_record_item);
-    
-    // set one-shot timer
-    timer_source_t heartbeat;
-    heartbeat.process = &heartbeat_handler;
-    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(&heartbeat);
-    
-    log_info("SPP loopback demo...\n\r");
-
-     // turn on!
-    hci_power_control(HCI_POWER_ON);
-
-    // go!
-    run_loop_execute();    
-
-    return 0;
-}
-#endif
--- a/spp_flowcontrol.cpp	Tue Jun 26 14:27:45 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-#if 0
-//*****************************************************************************
-//
-// spp_counter demo - it provides a SPP and sends a counter every second
-//
-// it doesn't use the LCD to get down to a minimal memory footpring
-//
-//*****************************************************************************
-#include "mbed.h"
-#include <btstack/hci_cmds.h>
-#include <btstack/run_loop.h>
-#include <btstack/sdp_util.h>
-#include "hci.h"
-#include "l2cap.h"
-#include "btstack_memory.h"
-#include "remote_device_db.h"
-#include "rfcomm.h"
-#include "sdp.h"
-#include "config.h"
-#include "debug.h"
-#include "bd_addr.h"  // class bd_addr
-
-Serial pc(USBTX, USBRX);
-DigitalOut led1(LED1), led2(LED2);
-
-#define HEARTBEAT_PERIOD_MS 500
-
-static uint8_t   rfcomm_channel_nr = 1;
-static uint16_t  rfcomm_channel_id = 0;
-static uint8_t   rfcomm_send_credit = 0;
-static uint8_t   spp_service_buffer[128];
-
-// Bluetooth logic
-static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
-    bd_addr_t event_addr;
-    uint8_t   rfcomm_channel_nr;
-    uint16_t  mtu;
-    
-    switch (packet_type) {
-        case HCI_EVENT_PACKET:
-            switch (packet[0]) {
-                    
-                case BTSTACK_EVENT_STATE:
-                    // bt stack activated, get started - set local name
-                    if (packet[2] == HCI_STATE_WORKING) {
-                        hci_send_cmd(&hci_write_local_name, "mbed-Demo");
-                    }
-                    break;
-                
-                case HCI_EVENT_COMMAND_COMPLETE:
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
-                        bt_flip_addr(event_addr, &packet[6]);
-                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
-                        break;
-                    }
-                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
-                        hci_discoverable_control(1);
-                        break;
-                    }
-                    break;
-
-                case HCI_EVENT_LINK_KEY_REQUEST:
-                    // deny link key request
-                    log_info("Link key request\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
-                    break;
-                    
-                case HCI_EVENT_PIN_CODE_REQUEST:
-                    // inform about pin code request
-                    log_info("Pin code request - using '0000'\n\r");
-                    bt_flip_addr(event_addr, &packet[2]);
-                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
-                    break;
-                
-                case RFCOMM_EVENT_INCOMING_CONNECTION:
-                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
-                    bt_flip_addr(event_addr, &packet[2]); 
-                    rfcomm_channel_nr = packet[8];
-                    rfcomm_channel_id = READ_BT_16(packet, 9);
-                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
-                    rfcomm_accept_connection_internal(rfcomm_channel_id);
-                    break;
-                    
-                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
-                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
-                    if (packet[2]) {
-                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
-                    } else {
-                        rfcomm_channel_id = READ_BT_16(packet, 12);
-                        mtu = READ_BT_16(packet, 14);
-                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
-                    }
-                    break;
-                    
-                case RFCOMM_EVENT_CHANNEL_CLOSED:
-                    rfcomm_channel_id = 0;
-                    break;
-                
-                default:
-                    break;
-            }
-            break;
-            
-        case RFCOMM_DATA_PACKET:
-            // hack: truncate data (we know that the packet is at least on byte bigger
-            packet[size] = 0;
-            puts( (const char *) packet);
-            rfcomm_send_credit = 1;
-        default:
-            break;
-    }
-}
-
-static void  heartbeat_handler(struct timer *ts){
-    if (rfcomm_send_credit){
-        rfcomm_grant_credits(rfcomm_channel_id, 1);
-        rfcomm_send_credit = 0;
-    }
-    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(ts);
-    led2 = !led2;
-} 
-
-// main
-int main(void)
-{
-    pc.baud(921600);
-    log_info("%s\n", __FILE__);
-
-    // init LEDs
-    led1 = led2 = 1;
-    
-    /// GET STARTED with BTstack ///
-    btstack_memory_init();
-    run_loop_init(RUN_LOOP_EMBEDDED);
-    
-    // init HCI
-    hci_transport_t* transport = hci_transport_usb_instance();
-    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
-    hci_init(transport, NULL, NULL, remote_db);
-    
-    // init L2CAP
-    l2cap_init();
-    l2cap_register_packet_handler(packet_handler);
-    
-    // init RFCOMM
-    rfcomm_init();
-    rfcomm_register_packet_handler(packet_handler);
-    rfcomm_register_service_with_initial_credits_internal(NULL, rfcomm_channel_nr, 100, 1);  // reserved channel, mtu=100, 1 credit
-
-    // init SDP, create record for SPP and register with SDP
-    sdp_init();
-    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
-    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
-    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
-    log_info("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
-    sdp_register_service_internal(NULL, service_record_item);
-    
-    // set one-shot timer
-    timer_source_t heartbeat;
-    heartbeat.process = &heartbeat_handler;
-    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
-    run_loop_add_timer(&heartbeat);
-    
-    
-    log_info("SPP FlowControl Demo: simulates processing on received data...\n\r");
-
-     // turn on!
-    hci_power_control(HCI_POWER_ON);
-
-    // go!
-    run_loop_execute();    
-    
-    // happy compiler!
-    return 0;
-}
-#endif