Junichi Katsu / Mbed 2 deprecated BLEControl

Dependencies:   FatFileSystem TB6612FNG2 mbed

Files at this revision

API Documentation at this revision

Comitter:
mbed_Cookbook_SE
Date:
Mon Nov 30 09:32:15 2015 +0000
Commit message:
??

Changed in this revision

.hg_archival.txt Show annotated file Show diff for this revision Revisions of this file
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/bt_control.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/btstack.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/hal_cpu.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/hal_tick.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/hci_cmds.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/linked_list.h Show annotated file Show diff for this revision Revisions of this file
BTstack/btstack/memory_pool.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/utils.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/btstack_memory.h 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/debug.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/hal_mbed/hal_cpu.cpp Show annotated file Show diff for this revision Revisions of this file
BTstack/hal_mbed/hal_tick.cpp 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/hci.h Show annotated file Show diff for this revision Revisions of this file
BTstack/hci_cmds.c Show annotated file Show diff for this revision Revisions of this file
BTstack/hci_dump.c Show annotated file Show diff for this revision Revisions of this file
BTstack/hci_dump.h Show annotated file Show diff for this revision Revisions of this file
BTstack/hci_transport.h Show annotated file Show diff for this revision Revisions of this file
BTstack/hci_transport_usb.cpp Show annotated file Show diff for this revision Revisions of this file
BTstack/l2cap.c Show annotated file Show diff for this revision Revisions of this file
BTstack/l2cap.h Show annotated file Show diff for this revision Revisions of this file
BTstack/l2cap_signaling.c Show annotated file Show diff for this revision Revisions of this file
BTstack/l2cap_signaling.h Show annotated file Show diff for this revision Revisions of this file
BTstack/linked_list.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/remote_device_db.h Show annotated file Show diff for this revision Revisions of this file
BTstack/remote_device_db_memory.c Show annotated file 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.c 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/utils.c Show annotated file Show diff for this revision Revisions of this file
FatFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TB6612FNG2.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
msc/msc.cpp Show annotated file Show diff for this revision Revisions of this file
msc/msc.h Show annotated file Show diff for this revision Revisions of this file
usb/UsbBaseClass.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbBaseClass.h Show annotated file Show diff for this revision Revisions of this file
usb/UsbDevice.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbDevice.h Show annotated file Show diff for this revision Revisions of this file
usb/UsbDevice2.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbEndpoint.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbEndpoint.h Show annotated file Show diff for this revision Revisions of this file
usb/UsbEndpoint2.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbHostMgr.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbHostMgr.h Show annotated file Show diff for this revision Revisions of this file
usb/UsbHostMgr2.cpp Show annotated file Show diff for this revision Revisions of this file
usb/UsbInc.h Show annotated file Show diff for this revision Revisions of this file
usb/Usb_td.cpp Show annotated file Show diff for this revision Revisions of this file
usb/Usb_td.h Show annotated file Show diff for this revision Revisions of this file
usb/Utils.cpp Show annotated file Show diff for this revision Revisions of this file
usb/Utils.h Show annotated file Show diff for this revision Revisions of this file
usb/mydbg.h Show annotated file Show diff for this revision Revisions of this file
usb/netCfg.h Show annotated file Show diff for this revision Revisions of this file
usb/usb_mem.c Show annotated file Show diff for this revision Revisions of this file
usb/usb_mem.h Show annotated file Show diff for this revision Revisions of this file
usbbt/bd_addr.cpp Show annotated file Show diff for this revision Revisions of this file
usbbt/bd_addr.h Show annotated file Show diff for this revision Revisions of this file
usbbt/usbbt.cpp Show annotated file Show diff for this revision Revisions of this file
usbbt/usbbt.h Show annotated file Show diff for this revision Revisions of this file
uvc/myjpeg.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/myjpeg.h Show annotated file Show diff for this revision Revisions of this file
uvc/stcamcfg.h Show annotated file Show diff for this revision Revisions of this file
uvc/usb_itd.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/usb_itd.h Show annotated file Show diff for this revision Revisions of this file
uvc/usb_mjpeg.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/usb_mjpeg.h Show annotated file Show diff for this revision Revisions of this file
uvc/uvc.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/uvc.h Show annotated file Show diff for this revision Revisions of this file
uvc/uvccfg.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/uvcctl.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/uvcini.cpp Show annotated file Show diff for this revision Revisions of this file
uvc/uvcsub.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hg_archival.txt	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,5 @@
+repo: 1ed23ab1345f9bd3b8f4a744fdff29557c42deeb
+node: cf06ba884429fb47b1126b7cd97291ac9b083d90
+branch: default
+latesttag: null
+latesttagdistance: 7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_demo.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,355 @@
+/*
+ * 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. This software may not be used in a commercial product
+ *    without an explicit license granted by the copyright holder.
+ *
+ * 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.
+ *
+ */
+
+//*****************************************************************************
+//
+// att device demo
+//
+//*****************************************************************************
+
+// TODO: seperate BR/EDR from LE ACL buffers
+// TODO: move LE init into HCI
+// ..
+
+// NOTE: Supports only a single connection
+
+// mbed specific
+#include "mbed.h"
+
+// 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 "btstack/hal_tick.h"
+
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "config.h"
+
+#include "att.h"
+#include "TB6612.h"
+
+Serial pc(USBTX, USBRX);
+TB6612 MOTOR_A(p21,p19,p20);
+TB6612 MOTOR_B(p22,p29,p30);
+
+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];
+
+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\x09mbed";
+    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;
+						MOTOR_A = 0;
+		                MOTOR_B = 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;
+
+                        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);
+
+    }
+    switch(handle) {
+            // Correspond to Characteristics 0xFFF1
+        case 0x000b:
+#if 0
+            if(buffer && ret<=buffer_size) {
+                buffer[0] = sw1.read();
+                log_info("Read value: %u\n", buffer[0]);
+            }
+            ret = 1;
+#else
+			ret = 0;
+            log_info("No action\n");
+#endif
+            break;
+
+            // Correspond to Characteristics 0xFFF2
+        case 0x000d:
+            if(buffer && buffer_size) {
+
+                buffer[0] = ledvalue;
+                log_info("Read value: %u\n", buffer[0]);
+            }
+            ret=1;
+            break;
+
+            // Correspond to Characteristics 0x00001234-0000-1000-8000-00805F9B34FB
+        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);
+
+    switch(handle) {
+            // Correspond to Characteristics 0xFFF1
+        case 0x000b:
+			switch(buffer[0])
+        	{
+            case 0x01:
+                MOTOR_A = 100;
+                MOTOR_B = 100;
+                break;
+            case 0x02:
+                MOTOR_A = -100;
+                MOTOR_B = -100;
+                break;
+            case 0x04:
+                MOTOR_A = 100;
+                MOTOR_B = -100;
+                break;
+            case 0x08:
+                MOTOR_A = -100;
+                MOTOR_B = 100;
+                break;
+            default:
+                MOTOR_A = 0;
+                MOTOR_B = 0;
+      	    }
+            break;
+
+            // Correspond to Characteristics 0xFFF2
+        case 0x000d:
+            log_info("New value: %u\n", buffer[0]);
+            ledvalue = buffer[0];
+            break;
+    }
+}
+
+
+void hal_tick_event(void)
+{
+    timer_counter++;
+}
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    //pc.baud(230400);
+    log_info("%s\n", __FILE__);
+
+    /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    hal_tick_set_handler(&hal_tick_event);
+
+    // 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;
+
+    log_info("Run...\n\n");
+
+    // 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	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,914 @@
+/*
+ * 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"
+#include "debug.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++){
+        log_info("%02X ", ((uint8_t *)data)[i]);
+    }
+    log_info("\n");
+}
+
+static void printUUID128(const uint8_t * uuid){
+    int i;
+    for (i=15; i >= 0 ; i--){
+        log_info("%02X", uuid[i]);
+        switch (i){
+            case 4:
+            case 6:
+            case 8:
+            case 10:
+                log_info("-");
+                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) {
+            log_info("Handle: END\n");
+            return;
+        }
+        log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags);
+        if (it.flags & ATT_PROPERTY_UUID128){
+            printUUID128(it.uuid);
+        } else {
+            log_info("%04x", READ_BT_16(it.uuid, 0));
+        }
+        log_info(", 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){
+    
+    log_info("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);
+        
+        // log_debug("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){
+    
+    log_info("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))){
+            
+            log_info("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){
+            log_info("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){
+    
+    log_info("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){
+    
+    log_info("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){
+    log_info("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){
+    log_info("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){
+    
+    log_info("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
+            // log_debug("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
+        // log_debug("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;
+                }
+            }
+            
+            // log_debug("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:
+            log_info("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	Mon Nov 30 09:32:15 2015 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/bt_control.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,76 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  bt_control.h
+ *
+ *  BT Control API -- allows BT Daemon to initialize and control differnt hardware
+ *
+ *  Created by Matthias Ringwald on 5/19/09.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    POWER_WILL_SLEEP = 1,
+    POWER_WILL_WAKE_UP
+} POWER_NOTIFICATION_t;
+
+typedef struct {
+    int          (*on)   (void *config);  // <-- turn BT module on and configure
+    int          (*off)  (void *config);  // <-- turn BT module off
+    int          (*sleep)(void *config);  // <-- put BT module to sleep    - only to be called after ON
+    int          (*wake) (void *config);  // <-- wake BT module from sleep - only to be called after SLEEP
+    int          (*valid)(void *config);  // <-- test if hardware can be supported
+    const char * (*name) (void *config);  // <-- return hardware name
+
+    /** support for UART baud rate changes - cmd has to be stored in hci_cmd_buffer
+     * @return have command
+     */
+    int          (*baudrate_cmd)(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer); 
+    
+    /** support custom init sequences after RESET command - cmd has to be stored in hci_cmd_buffer
+      * @return have command
+      */
+    int          (*next_cmd)(void *config, uint8_t * hci_cmd_buffer); 
+
+    void         (*register_for_power_notifications)(void (*cb)(POWER_NOTIFICATION_t event));
+
+    void         (*hw_error)(void); 
+} bt_control_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/btstack.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ */
+
+/*
+ *  btstack.h
+ *
+ *  Created by Matthias Ringwald on 7/1/09.
+ *
+ *  BTstack client API
+ *  
+ */
+
+#pragma once
+
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/utils.h>
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+// Default TCP port for BTstack daemon
+#define BTSTACK_PORT            13333
+
+// UNIX domain socket for BTstack */
+#define BTSTACK_UNIX            "/tmp/BTstack"
+
+// packet handler
+typedef void (*btstack_packet_handler_t) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+
+// optional: if called before bt_open, TCP socket is used instead of local unix socket
+//           note: address is not copied and must be valid during bt_open
+void bt_use_tcp(const char * address, uint16_t port); 
+
+// init BTstack library
+int bt_open(void);
+
+// stop using BTstack library
+int bt_close(void);
+
+// send hci cmd packet
+int bt_send_cmd(const hci_cmd_t *cmd, ...);
+
+// register packet handler -- channel only valid for l2cap and rfcomm packets
+// @returns old packet handler
+btstack_packet_handler_t bt_register_packet_handler(btstack_packet_handler_t handler);
+
+void bt_send_acl(uint8_t * data, uint16_t len);
+
+void bt_send_l2cap(uint16_t local_cid, uint8_t *data, uint16_t len);
+void bt_send_rfcomm(uint16_t rfcom_cid, uint8_t *data, uint16_t len);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hal_cpu.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *  hal_cpu.h
+ *
+ *  Low power mode for MCU requires that IRQs can be first blocked 
+ *  and then unblocked while entering low power mode atomically
+ */
+ 
+void hal_cpu_disable_irqs(void);
+void hal_cpu_enable_irqs(void);
+void hal_cpu_enable_irqs_and_sleep(void);
+
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hal_tick.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *  hal_tick.h
+ *
+ *  Hardware abstraction layer for periodic ticks
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+void hal_tick_init(void);
+void hal_tick_set_handler(void (*tick_handler)(void));
+int  hal_tick_get_tick_period_in_ms(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hci_cmds.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ */
+
+/*
+ *  hci_cmds.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+/**
+ * packet types - used in BTstack and over the H4 UART interface
+ */
+#define HCI_COMMAND_DATA_PACKET	0x01
+#define HCI_ACL_DATA_PACKET	    0x02
+#define HCI_SCO_DATA_PACKET	    0x03
+#define HCI_EVENT_PACKET	    0x04
+
+// extension for client/server communication
+#define DAEMON_EVENT_PACKET     0x05
+    
+// L2CAP data
+#define L2CAP_DATA_PACKET       0x06
+
+// RFCOMM data
+#define RFCOMM_DATA_PACKET      0x07
+
+// Attribute protocol data
+#define ATT_DATA_PACKET         0x08
+
+// Security Manager protocol data
+#define SM_DATA_PACKET          0x09
+    
+// debug log messages
+#define LOG_MESSAGE_PACKET      0xfc
+
+    
+// Fixed PSM numbers
+#define PSM_SDP    0x01
+#define PSM_RFCOMM 0x03
+#define PSM_HID_CONTROL 0x11
+#define PSM_HID_INTERRUPT 0x13
+
+// Events from host controller to host
+#define HCI_EVENT_INQUIRY_COMPLETE				           0x01
+#define HCI_EVENT_INQUIRY_RESULT				           0x02
+#define HCI_EVENT_CONNECTION_COMPLETE			           0x03
+#define HCI_EVENT_CONNECTION_REQUEST			           0x04
+#define HCI_EVENT_DISCONNECTION_COMPLETE		      	   0x05
+#define HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT            0x06
+#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE	           0x07
+#define HCI_EVENT_ENCRYPTION_CHANGE                        0x08
+#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE      0x09
+#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE                 0x0A
+#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE  0x0B
+#define HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
+#define HCI_EVENT_QOS_SETUP_COMPLETE			           0x0D
+#define HCI_EVENT_COMMAND_COMPLETE				           0x0E
+#define HCI_EVENT_COMMAND_STATUS				           0x0F
+#define HCI_EVENT_HARDWARE_ERROR                           0x10
+#define HCI_EVENT_FLUSH_OCCURED                            0x11
+#define HCI_EVENT_ROLE_CHANGE				               0x12
+#define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS	      	   0x13
+#define HCI_EVENT_MODE_CHANGE_EVENT                        0x14
+#define HCI_EVENT_RETURN_LINK_KEYS                         0x15
+#define HCI_EVENT_PIN_CODE_REQUEST                         0x16
+#define HCI_EVENT_LINK_KEY_REQUEST                         0x17
+#define HCI_EVENT_LINK_KEY_NOTIFICATION                    0x18
+#define HCI_EVENT_DATA_BUFFER_OVERFLOW                     0x1A
+#define HCI_EVENT_MAX_SLOTS_CHANGED			               0x1B
+#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE               0x1C
+#define HCI_EVENT_PACKET_TYPE_CHANGED                      0x1D
+#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI		      	   0x22
+#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE                0x2F
+#define HCI_EVENT_LE_META                                  0x3E
+#define HCI_EVENT_VENDOR_SPECIFIC				           0xFF
+
+#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE                0x01
+#define HCI_SUBEVENT_LE_ADVERTISING_REPORT                 0x02
+#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE         0x03
+#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
+#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST              0x05
+    
+// last used HCI_EVENT in 2.1 is 0x3d
+
+// events 0x50-0x5f are used internally
+
+// BTSTACK DAEMON EVENTS
+
+// events from BTstack for application/client lib
+#define BTSTACK_EVENT_STATE                                0x60
+
+// data: event(8), len(8), nr hci connections
+#define BTSTACK_EVENT_NR_CONNECTIONS_CHANGED               0x61
+
+// data: none
+#define BTSTACK_EVENT_POWERON_FAILED                       0x62
+
+// data: majot (8), minor (8), revision(16)
+#define BTSTACK_EVENT_VERSION	        				   0x63
+
+// data: system bluetooth on/off (bool)
+#define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED			   0x64
+
+// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes)
+#define BTSTACK_EVENT_REMOTE_NAME_CACHED	     		   0x65
+
+// data: discoverable enabled (bool)
+#define BTSTACK_EVENT_DISCOVERABLE_ENABLED			       0x66
+
+// L2CAP EVENTS
+	
+// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 
+#define L2CAP_EVENT_CHANNEL_OPENED                         0x70
+
+// data: event (8), len(8), channel (16)
+#define L2CAP_EVENT_CHANNEL_CLOSED                         0x71
+
+// data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) 
+#define L2CAP_EVENT_INCOMING_CONNECTION					   0x72
+
+// data: event(8), len(8), handle(16)
+#define L2CAP_EVENT_TIMEOUT_CHECK                          0x73
+
+// data: event(8), len(8), local_cid(16), credits(8)
+#define L2CAP_EVENT_CREDITS								   0x74
+
+// data: event(8), len(8), status (8), psm (16)
+#define L2CAP_EVENT_SERVICE_REGISTERED                     0x75
+
+
+// RFCOMM EVENTS
+	
+// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
+#define RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE                 0x80
+	
+// data: event(8), len(8), rfcomm_cid(16)
+#define RFCOMM_EVENT_CHANNEL_CLOSED                        0x81
+	
+// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+#define RFCOMM_EVENT_INCOMING_CONNECTION                   0x82
+	
+// data: event (8), len(8), rfcommid (16), ...
+#define RFCOMM_EVENT_REMOTE_LINE_STATUS                    0x83
+	
+// data: event(8), len(8), rfcomm_cid(16), credits(8)
+#define RFCOMM_EVENT_CREDITS			                   0x84
+	
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_SERVICE_REGISTERED                    0x85
+    
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_PERSISTENT_CHANNEL                    0x86
+    
+    
+// data: event(8), len(8), status(8), service_record_handle(32)
+#define SDP_SERVICE_REGISTERED                             0x90
+
+	
+// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors
+
+#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED              0x50
+#define BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH		   0x51
+#define BTSTACK_ACTIVATION_POWERON_FAILED       		   0x52
+#define BTSTACK_ACTIVATION_FAILED_UNKNOWN       		   0x53
+#define BTSTACK_NOT_ACTIVATED							   0x54
+#define BTSTACK_BUSY									   0x55
+#define BTSTACK_MEMORY_ALLOC_FAILED                        0x56
+#define BTSTACK_ACL_BUFFERS_FULL                           0x57
+
+// l2cap errors - enumeration by the command that created them
+#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60
+#define L2CAP_COMMAND_REJECT_REASON_SIGNALING_MTU_EXCEEDED 0x61
+#define L2CAP_COMMAND_REJECT_REASON_INVALID_CID_IN_REQUEST 0x62
+
+#define L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL        0x63
+#define L2CAP_CONNECTION_RESPONSE_RESULT_PENDING           0x64
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_PSM       0x65
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY  0x66
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES 0x65
+
+#define L2CAP_CONFIG_RESPONSE_RESULT_SUCCESSFUL            0x66
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNACCEPTABLE_PARAMS   0x67
+#define L2CAP_CONFIG_RESPONSE_RESULT_REJECTED              0x68
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS       0x69
+#define L2CAP_SERVICE_ALREADY_REGISTERED                   0x6a
+    
+#define RFCOMM_MULTIPLEXER_STOPPED                         0x70
+#define RFCOMM_CHANNEL_ALREADY_REGISTERED                  0x71
+#define RFCOMM_NO_OUTGOING_CREDITS                         0x72
+
+#define SDP_HANDLE_ALREADY_REGISTERED                      0x80
+ 
+/**
+ * Default INQ Mode
+ */
+#define HCI_INQUIRY_LAP 0x9E8B33L  // 0x9E8B33: General/Unlimited Inquiry Access Code (GIAC)
+/**
+ *  Hardware state of Bluetooth controller 
+ */
+typedef enum {
+    HCI_POWER_OFF = 0,
+    HCI_POWER_ON,
+	HCI_POWER_SLEEP
+} HCI_POWER_MODE;
+
+/**
+ * State of BTstack 
+ */
+typedef enum {
+    HCI_STATE_OFF = 0,
+    HCI_STATE_INITIALIZING,
+    HCI_STATE_WORKING,
+    HCI_STATE_HALTING,
+	HCI_STATE_SLEEPING,
+	HCI_STATE_FALLING_ASLEEP
+} HCI_STATE;
+
+/** 
+ * compact HCI Command packet description
+ */
+ typedef struct {
+    uint16_t    opcode;
+    const char *format;
+} hci_cmd_t;
+
+
+// HCI Commands - see hci_cmds.c for info on parameters
+extern const hci_cmd_t btstack_get_state;
+extern const hci_cmd_t btstack_set_power_mode;
+extern const hci_cmd_t btstack_set_acl_capture_mode;
+extern const hci_cmd_t btstack_get_version;
+extern const hci_cmd_t btstack_get_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_discoverable;
+extern const hci_cmd_t btstack_set_bluetooth_enabled;    // only used by btstack config
+	
+extern const hci_cmd_t hci_accept_connection_request;
+extern const hci_cmd_t hci_authentication_requested;
+extern const hci_cmd_t hci_change_connection_link_key;
+extern const hci_cmd_t hci_create_connection;
+extern const hci_cmd_t hci_create_connection_cancel;
+extern const hci_cmd_t hci_delete_stored_link_key;
+extern const hci_cmd_t hci_disconnect;
+extern const hci_cmd_t hci_host_buffer_size;
+extern const hci_cmd_t hci_inquiry;
+extern const hci_cmd_t hci_inquiry_cancel;
+extern const hci_cmd_t hci_link_key_request_negative_reply;
+extern const hci_cmd_t hci_link_key_request_reply;
+extern const hci_cmd_t hci_pin_code_request_reply;
+extern const hci_cmd_t hci_pin_code_request_negative_reply;
+extern const hci_cmd_t hci_qos_setup;
+extern const hci_cmd_t hci_read_bd_addr;
+extern const hci_cmd_t hci_read_buffer_size;
+extern const hci_cmd_t hci_read_le_host_supported;
+extern const hci_cmd_t hci_read_link_policy_settings;
+extern const hci_cmd_t hci_read_link_supervision_timeout;
+extern const hci_cmd_t hci_read_local_supported_features;
+extern const hci_cmd_t hci_read_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_reject_connection_request;
+extern const hci_cmd_t hci_remote_name_request;
+extern const hci_cmd_t hci_remote_name_request_cancel;
+extern const hci_cmd_t hci_reset;
+extern const hci_cmd_t hci_role_discovery;
+extern const hci_cmd_t hci_set_event_mask;
+extern const hci_cmd_t hci_set_connection_encryption;
+extern const hci_cmd_t hci_sniff_mode;
+extern const hci_cmd_t hci_switch_role_command;
+extern const hci_cmd_t hci_write_authentication_enable;
+extern const hci_cmd_t hci_write_class_of_device;
+extern const hci_cmd_t hci_write_extended_inquiry_response;
+extern const hci_cmd_t hci_write_inquiry_mode;
+extern const hci_cmd_t hci_write_le_host_supported;
+extern const hci_cmd_t hci_write_link_policy_settings;
+extern const hci_cmd_t hci_write_link_supervision_timeout;
+extern const hci_cmd_t hci_write_local_name;
+extern const hci_cmd_t hci_write_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_write_page_timeout;
+extern const hci_cmd_t hci_write_scan_enable;
+extern const hci_cmd_t hci_write_simple_pairing_mode;
+
+extern const hci_cmd_t hci_le_add_device_to_whitelist;
+extern const hci_cmd_t hci_le_clear_white_list;
+extern const hci_cmd_t hci_le_connection_update;
+extern const hci_cmd_t hci_le_create_connection;
+extern const hci_cmd_t hci_le_create_connection_cancel;
+extern const hci_cmd_t hci_le_encrypt;
+extern const hci_cmd_t hci_le_long_term_key_negative_reply;
+extern const hci_cmd_t hci_le_long_term_key_request_reply;
+extern const hci_cmd_t hci_le_rand;
+extern const hci_cmd_t hci_le_read_advertising_channel_tx_power;
+extern const hci_cmd_t hci_le_read_buffer_size ;
+extern const hci_cmd_t hci_le_read_channel_map;
+extern const hci_cmd_t hci_le_read_remote_used_features;
+extern const hci_cmd_t hci_le_read_supported_features;
+extern const hci_cmd_t hci_le_read_supported_states;
+extern const hci_cmd_t hci_le_read_white_list_size;
+extern const hci_cmd_t hci_le_receiver_test;
+extern const hci_cmd_t hci_le_remove_device_from_whitelist;
+extern const hci_cmd_t hci_le_set_advertise_enable;
+extern const hci_cmd_t hci_le_set_advertising_data;
+extern const hci_cmd_t hci_le_set_advertising_parameters;
+extern const hci_cmd_t hci_le_set_event_mask;
+extern const hci_cmd_t hci_le_set_host_channel_classification;
+extern const hci_cmd_t hci_le_set_random_address;
+extern const hci_cmd_t hci_le_set_scan_enable;
+extern const hci_cmd_t hci_le_set_scan_parameters;
+extern const hci_cmd_t hci_le_set_scan_response_data;
+extern const hci_cmd_t hci_le_start_encryption;
+extern const hci_cmd_t hci_le_test_end;
+extern const hci_cmd_t hci_le_transmitter_test;
+    
+extern const hci_cmd_t l2cap_accept_connection;
+extern const hci_cmd_t l2cap_create_channel;
+extern const hci_cmd_t l2cap_create_channel_mtu;
+extern const hci_cmd_t l2cap_decline_connection;
+extern const hci_cmd_t l2cap_disconnect;
+extern const hci_cmd_t l2cap_register_service;
+extern const hci_cmd_t l2cap_unregister_service;
+
+extern const hci_cmd_t sdp_register_service_record;
+extern const hci_cmd_t sdp_unregister_service_record;
+
+// accept connection @param bd_addr(48), rfcomm_cid (16)
+extern const hci_cmd_t rfcomm_accept_connection;
+// create rfcomm channel: @param bd_addr(48), channel (8)
+extern const hci_cmd_t rfcomm_create_channel;
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+extern const hci_cmd_t rfcomm_create_channel_with_initial_credits;
+// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
+extern const hci_cmd_t rfcomm_decline_connection;
+// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
+extern const hci_cmd_t rfcomm_disconnect;
+// register rfcomm service: @param channel(8), mtu (16)
+extern const hci_cmd_t rfcomm_register_service;
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
+// unregister rfcomm service, @param service_channel(16)
+extern const hci_cmd_t rfcomm_unregister_service;
+// request persisten rfcomm channel for service name: serive name (char*) 
+extern const hci_cmd_t rfcomm_persistent_channel_for_service;
+    
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/linked_list.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ */
+
+/*
+ *  linked_list.h
+ *
+ *  Created by Matthias Ringwald on 7/13/09.
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+typedef struct linked_item {
+    struct linked_item *next; // <-- next element in list, or NULL
+    void *user_data;          // <-- pointer to struct base
+} linked_item_t;
+
+typedef linked_item_t * linked_list_t;
+
+void linked_item_set_user(linked_item_t *item, void *user_data);        // <-- set user data
+void * linked_item_get_user(linked_item_t *item);                       // <-- get user data
+int  linked_list_empty(linked_list_t * list);
+void linked_list_add(linked_list_t * list, linked_item_t *item);        // <-- add item to list as first element
+void linked_list_add_tail(linked_list_t * list, linked_item_t *item);   // <-- add item to list as last element
+int  linked_list_remove(linked_list_t * list, linked_item_t *item);     // <-- remove item from list
+linked_item_t * linked_list_get_last_item(linked_list_t * list);        // <-- find the last item in the list
+
+void test_linked_list(void);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/memory_pool.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,54 @@
+/*
+ * 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.h
+ *
+ *  @Brief Fixed-size block allocation
+ *
+ *  @Assumption block_size >= sizeof(void *)
+ *  @Assumption size of storage >= count * block_size
+ *
+ *  @Note minimal implementation, no error checking/handling
+ */
+
+#pragma once
+
+typedef void * memory_pool_t;
+
+// initialize memory pool with with given storage, block size and count
+void   memory_pool_create(memory_pool_t *pool, void * storage, int count, int block_size);
+
+// get free block from pool, @returns NULL or pointer to block
+void * memory_pool_get(memory_pool_t *pool);
+
+// return previously reserved block to memory pool
+void   memory_pool_free(memory_pool_t *pool, void * block);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/run_loop.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ */
+
+/*
+ *  run_loop.h
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include "btstack/linked_list.h"
+
+#include <stdint.h>
+
+#ifdef HAVE_TIME
+#include <sys/time.h>
+#endif
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+typedef enum {
+    RUN_LOOP_POSIX = 1,
+    RUN_LOOP_COCOA,
+    RUN_LOOP_EMBEDDED
+} RUN_LOOP_TYPE;
+
+typedef struct data_source {
+    linked_item_t item;
+    int  fd;                                 // <-- file descriptor to watch or 0
+    int  (*process)(struct data_source *ds); // <-- do processing
+} data_source_t;
+
+typedef struct timer {
+    linked_item_t item; 
+#ifdef HAVE_TIME
+    struct timeval timeout;                  // <-- next timeout
+#endif
+#ifdef HAVE_TICK
+    uint32_t timeout;                       // timeout in system ticks
+#endif
+    void  (*process)(struct timer *ts);      // <-- do processing
+} timer_source_t;
+
+
+// set timer based on current time
+void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms);
+
+// add/remove timer_source
+void run_loop_add_timer(timer_source_t *timer); 
+int  run_loop_remove_timer(timer_source_t *timer);
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type);
+
+// add/remove data_source
+void run_loop_add_data_source(data_source_t *dataSource);
+int  run_loop_remove_data_source(data_source_t *dataSource);
+
+
+// execute configured run_loop
+void run_loop_execute(void);
+
+// hack to fix HCI timer handling
+#ifdef HAVE_TICK
+uint32_t embedded_get_ticks(void);
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms);
+#endif
+#ifdef EMBEDDED
+void     embedded_trigger(void);    
+#endif
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/sdp_util.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/utils.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 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.
+ *
+ */
+
+/*
+ *  utils.h
+ *
+ *  General utility functions
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/**
+ * @brief hci connection handle type
+ */
+typedef uint16_t hci_con_handle_t;
+
+/**
+ * @brief Length of a bluetooth device address.
+ */
+#define BD_ADDR_LEN 6
+typedef uint8_t bd_addr_t[BD_ADDR_LEN];
+
+/**
+ * @brief The link key type
+ */
+#define LINK_KEY_LEN 16
+typedef uint8_t link_key_t[LINK_KEY_LEN]; 
+
+/**
+ * @brief The device name type
+ */
+#define DEVICE_NAME_LEN 248
+typedef uint8_t device_name_t[DEVICE_NAME_LEN+1]; 
+	
+	
+// helper for BT little endian format
+#define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
+#define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16))
+#define READ_BT_32( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16) | (((uint32_t) buffer[pos+3])) << 24)
+
+// helper for SDP big endian format
+#define READ_NET_16( buffer, pos) ( ((uint16_t) buffer[pos+1]) | (((uint16_t)buffer[pos  ]) << 8))
+#define READ_NET_32( buffer, pos) ( ((uint32_t) buffer[pos+3]) | (((uint32_t)buffer[pos+2]) << 8) | (((uint32_t)buffer[pos+1]) << 16) | (((uint32_t) buffer[pos])) << 24)
+
+// HCI CMD OGF/OCF
+#define READ_CMD_OGF(buffer) (buffer[1] >> 2)
+#define READ_CMD_OCF(buffer) ((buffer[1] & 0x03) << 8 | buffer[0])
+
+// check if command complete event for given command
+#define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode)
+#define COMMAND_STATUS_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_STATUS && READ_BT_16(event,4) == cmd.opcode)
+
+// Code+Len=2, Pkts+Opcode=3; total=5
+#define OFFSET_OF_DATA_IN_COMMAND_COMPLETE 5
+
+// ACL Packet
+#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff)
+#define READ_ACL_FLAGS( buffer )      ( buffer[1] >> 4 )
+#define READ_ACL_LENGTH( buffer )     (READ_BT_16(buffer, 2))
+
+// L2CAP Packet
+#define READ_L2CAP_LENGTH(buffer)     ( READ_BT_16(buffer, 4))
+#define READ_L2CAP_CHANNEL_ID(buffer) ( READ_BT_16(buffer, 6))
+
+void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+void bt_flip_addr(bd_addr_t dest, bd_addr_t src);
+
+void net_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+
+void hexdump(void *data, int size);
+void printUUID(uint8_t *uuid);
+
+// @deprecated please use more convenient bd_addr_to_str
+void print_bd_addr( bd_addr_t addr);
+char * bd_addr_to_str(bd_addr_t addr);
+
+int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
+    
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum);
+uint8_t crc8_calc(uint8_t *data, uint16_t len);
+
+#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
+#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
+
+#if defined __cplusplus
+}
+#endif
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack_memory.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack_memory.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,73 @@
+/*
+ * 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
+ *
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+void btstack_memory_init(void);
+
+void * btstack_memory_hci_connection_get(void);
+void   btstack_memory_hci_connection_free(void *hci_connection);
+void * btstack_memory_l2cap_service_get(void);
+void   btstack_memory_l2cap_service_free(void *l2cap_service);
+void * btstack_memory_l2cap_channel_get(void);
+void   btstack_memory_l2cap_channel_free(void *l2cap_channel);
+void * btstack_memory_rfcomm_multiplexer_get(void);
+void   btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer);
+void * btstack_memory_rfcomm_service_get(void);
+void   btstack_memory_rfcomm_service_free(void *rfcomm_service);
+void * btstack_memory_rfcomm_channel_get(void);
+void   btstack_memory_rfcomm_channel_free(void *rfcomm_channel);
+void * btstack_memory_db_mem_device_name_get(void);
+void   btstack_memory_db_mem_device_name_free(void *db_mem_device_name);
+void * btstack_memory_db_mem_device_link_key_get(void);
+void   btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key);
+void * btstack_memory_db_mem_service_get(void);
+void   btstack_memory_db_mem_service_free(void *db_mem_service);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/config.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,29 @@
+// Replaced by LE version
+
+#define EMBEDDED
+
+//#define ENABLE_LOG_DEBUG
+#define ENABLE_LOG_INFO
+#define ENABLE_LOG_ERROR
+
+//#define HAVE_INIT_SCRIPT
+#define HAVE_TICK
+
+//#define HAVE_EHCILL
+#define HAVE_BLE
+
+#define ASYNC_BUFFERS 1
+
+
+#define HCI_ACL_PAYLOAD_SIZE 52
+
+// 
+#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/debug.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,76 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  debug.h
+ *
+ *  allow to funnel debug & error messages 
+ */
+
+#include "config.h"
+#include "hci_dump.h"
+
+#include <stdio.h>
+
+#ifdef ENABLE_LOG_DEBUG
+#ifdef HAVE_HCI_DUMP
+#define log_debug(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_debug(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_debug(...)
+#endif
+
+#ifdef ENABLE_LOG_INFO
+#ifdef HAVE_HCI_DUMP
+#define log_info(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_info(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_info(...)
+#endif
+
+#ifdef ENABLE_LOG_ERROR
+#ifdef HAVE_HCI_DUMP
+#define log_error(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_error(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_error(...)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/global.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,10 @@
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+
+extern uint8_t  startup_state = 0;
+extern uint8_t  connection_status = 0;
+extern unsigned led1_on_count = 0;
+extern uint8_t  led1_on_state = 0;
+extern unsigned timer_counter = 0;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hal_mbed/hal_cpu.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *  hal_cpu.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_cpu.h>
+
+void hal_cpu_disable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs_and_sleep(){
+    
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hal_mbed/hal_tick.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *  hal_tick.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_tick.h>
+#include "mbed.h"
+static Ticker tick;
+
+static void dummy_handler(void){};
+
+static void (*tick_handler)(void) = &dummy_handler;
+
+void hal_tick_init(void){
+
+}
+
+void hal_tick_set_handler(void (*handler)(void)){
+    if (handler == NULL){
+        tick_handler = &dummy_handler;
+        return;
+    }
+    tick_handler = handler;
+    tick.attach(tick_handler, 0.001);
+}
+
+int  hal_tick_get_tick_period_in_ms(void){
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,1409 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci.c
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#include "config.h"
+
+#include "hci.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef EMBEDDED
+#include <unistd.h> // gethostbyname
+#include <btstack/version.h>
+#endif
+
+#include "btstack_memory.h"
+#include "debug.h"
+#include "hci_dump.h"
+
+#include "btstack/hci_cmds.h"
+
+#define HCI_CONNECTION_TIMEOUT_MS 10000
+
+#ifdef USE_BLUETOOL
+#include "bt_control_iphone.h"
+#endif
+
+static void hci_update_scan_enable(void);
+
+// the STACK is here
+static hci_stack_t       hci_stack;
+
+/**
+ * get connection for a given handle
+ *
+ * @return connection OR NULL, if not found
+ */
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ((hci_connection_t *) it)->con_handle == con_handle){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+static void hci_connection_timeout_handler(timer_source_t *timer){
+    hci_connection_t * connection = (hci_connection_t *) linked_item_get_user(&timer->item);
+#ifdef HAVE_TIME
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    if (tv.tv_sec >= connection->timestamp.tv_sec + HCI_CONNECTION_TIMEOUT_MS/1000) {
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+#ifdef HAVE_TICK
+    if (embedded_get_ticks() > connection->timestamp + embedded_ticks_for_ms(HCI_CONNECTION_TIMEOUT_MS)){
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+    run_loop_set_timer(timer, HCI_CONNECTION_TIMEOUT_MS);
+    run_loop_add_timer(timer);
+}
+
+static void hci_connection_timestamp(hci_connection_t *connection){
+#ifdef HAVE_TIME
+    gettimeofday(&connection->timestamp, NULL);
+#endif
+#ifdef HAVE_TICK
+    connection->timestamp = embedded_get_ticks();
+#endif
+}
+
+/**
+ * create connection for given address
+ *
+ * @return connection OR NULL, if no memory left
+ */
+static hci_connection_t * create_connection_for_addr(bd_addr_t addr){
+    hci_connection_t * conn = (hci_connection_t *) btstack_memory_hci_connection_get();
+    if (!conn) return NULL;
+    BD_ADDR_COPY(conn->address, addr);
+    conn->con_handle = 0xffff;
+    conn->authentication_flags = AUTH_FLAGS_NONE;
+    linked_item_set_user(&conn->timeout.item, conn);
+    conn->timeout.process = hci_connection_timeout_handler;
+    hci_connection_timestamp(conn);
+    conn->acl_recombination_length = 0;
+    conn->acl_recombination_pos = 0;
+    conn->num_acl_packets_sent = 0;
+    linked_list_add(&hci_stack.connections, (linked_item_t *) conn);
+    return conn;
+}
+
+/**
+ * get connection for given address
+ *
+ * @return connection OR NULL, if not found
+ */
+static hci_connection_t * connection_for_address(bd_addr_t address){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ! BD_ADDR_CMP( ((hci_connection_t *) it)->address, address) ){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+inline static void connectionSetAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags | flags);
+}
+
+inline static void connectionClearAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags & ~flags);
+}
+
+
+/**
+ * add authentication flags and reset timer
+ */
+static void hci_add_connection_flags_for_flipped_bd_addr(uint8_t *bd_addr, hci_authentication_flags_t flags){
+    bd_addr_t addr;
+    bt_flip_addr(addr, *(bd_addr_t *) bd_addr);
+    hci_connection_t * conn = connection_for_address(addr);
+    if (conn) {
+        connectionSetAuthenticationFlags(conn, flags);
+        hci_connection_timestamp(conn);
+    }
+}
+
+int  hci_authentication_active_for_handle(hci_con_handle_t handle){
+    hci_connection_t * conn = connection_for_handle(handle);
+    if (!conn) return 0;
+    if (!conn->authentication_flags) return 0;
+    if (conn->authentication_flags & SENT_LINK_KEY_REPLY) return 0;
+    if (conn->authentication_flags & RECV_LINK_KEY_NOTIFICATION) return 0;
+    return 1;
+}
+
+void hci_drop_link_key_for_bd_addr(bd_addr_t *addr){
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->delete_link_key(addr);
+    }
+}
+
+
+/**
+ * count connections
+ */
+static int nr_hci_connections(void){
+    int count = 0;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next, count++);
+    return count;
+}
+
+/** 
+ * Dummy handler called by HCI
+ */
+static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+}
+
+uint8_t hci_number_outgoing_packets(hci_con_handle_t handle){
+    hci_connection_t * connection = connection_for_handle(handle);
+    if (!connection) {
+        log_error("hci_number_outgoing_packets connectino for handle %u does not exist!\n", handle);
+        return 0;
+    }
+    return connection->num_acl_packets_sent;
+}
+
+uint8_t hci_number_free_acl_slots(){
+    uint8_t free_slots = hci_stack.total_num_acl_packets;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        hci_connection_t * connection = (hci_connection_t *) it;
+        if (free_slots < connection->num_acl_packets_sent) {
+            log_error("hci_number_free_acl_slots: sum of outgoing packets > total acl packets!\n");
+            return 0;
+        }
+        free_slots -= connection->num_acl_packets_sent;
+    }
+    return free_slots;
+}
+
+int hci_can_send_packet_now(uint8_t packet_type){
+
+    // check for async hci transport implementations
+    if (hci_stack.hci_transport->can_send_packet_now){
+        if (!hci_stack.hci_transport->can_send_packet_now(packet_type)){
+            return 0;
+        }
+    }
+    
+    // check regular Bluetooth flow control
+    switch (packet_type) {
+        case HCI_ACL_DATA_PACKET:
+            return hci_number_free_acl_slots();
+        case HCI_COMMAND_DATA_PACKET:
+            return hci_stack.num_cmd_packets;
+        default:
+            return 0;
+    }
+}
+
+int hci_send_acl_packet(uint8_t *packet, int size){
+
+    // check for free places on BT module
+    if (!hci_number_free_acl_slots()) return BTSTACK_ACL_BUFFERS_FULL;
+    
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *connection = connection_for_handle( con_handle);
+    if (!connection) return 0;
+    hci_connection_timestamp(connection);
+    
+    // count packet
+    connection->num_acl_packets_sent++;
+    // log_info("hci_send_acl_packet - handle %u, sent %u\n", connection->con_handle, connection->num_acl_packets_sent);
+
+    // send packet 
+    int err = hci_stack.hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
+    
+    return err;
+}
+
+static void acl_handler(uint8_t *packet, int size){
+
+    // get info
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *conn      = connection_for_handle(con_handle);
+    uint8_t  acl_flags          = READ_ACL_FLAGS(packet);
+    uint16_t acl_length         = READ_ACL_LENGTH(packet);
+
+    // ignore non-registered handle
+    if (!conn){
+        log_error( "hci.c: acl_handler called with non-registered handle %u!\n" , con_handle);
+        return;
+    }
+    
+    // update idle timestamp
+    hci_connection_timestamp(conn);
+    
+    // handle different packet types
+    switch (acl_flags & 0x03) {
+            
+        case 0x01: // continuation fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos == 0) {
+                log_error( "ACL Cont Fragment but no first fragment for handle 0x%02x\n", con_handle);
+                return;
+            }
+            
+            // append fragment payload (header already stored)
+            memcpy(&conn->acl_recombination_buffer[conn->acl_recombination_pos], &packet[4], acl_length );
+            conn->acl_recombination_pos += acl_length;
+            
+            // log_error( "ACL Cont Fragment: acl_len %u, combined_len %u, l2cap_len %u\n", acl_length,
+            //        conn->acl_recombination_pos, conn->acl_recombination_length);  
+            
+            // forward complete L2CAP packet if complete. 
+            if (conn->acl_recombination_pos >= conn->acl_recombination_length + 4 + 4){ // pos already incl. ACL header
+                
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, conn->acl_recombination_buffer, conn->acl_recombination_pos);
+                // reset recombination buffer
+                conn->acl_recombination_length = 0;
+                conn->acl_recombination_pos = 0;
+            }
+            break;
+            
+        case 0x02: { // first fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos) {
+                log_error( "ACL First Fragment but data in buffer for handle 0x%02x\n", con_handle);
+                return;
+            }
+
+            // peek into L2CAP packet!
+            uint16_t l2cap_length = READ_L2CAP_LENGTH( packet );
+
+            // log_error( "ACL First Fragment: acl_len %u, l2cap_len %u\n", acl_length, l2cap_length);
+
+            // compare fragment size to L2CAP packet size
+            if (acl_length >= l2cap_length + 4){
+                
+                // forward fragment as L2CAP packet
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, packet, acl_length + 4);
+            
+            } else {
+                // store first fragment and tweak acl length for complete package
+                memcpy(conn->acl_recombination_buffer, packet, acl_length + 4);
+                conn->acl_recombination_pos    = acl_length + 4;
+                conn->acl_recombination_length = l2cap_length;
+                bt_store_16(conn->acl_recombination_buffer, 2, l2cap_length +4);
+            }
+            break;
+            
+        } 
+        default:
+            log_error( "hci.c: acl_handler called with invalid packet boundary flags %u\n", acl_flags & 0x03);
+            return;
+    }
+    
+    // execute main loop
+    hci_run();
+}
+
+static void hci_shutdown_connection(hci_connection_t *conn){
+    log_info("Connection closed: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+
+    // cancel all l2cap connections
+    hci_emit_disconnection_complete(conn->con_handle, 0x16);    // terminated by local host
+
+    run_loop_remove_timer(&conn->timeout);
+    
+    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+    btstack_memory_hci_connection_free( conn );
+    
+    // now it's gone
+    hci_emit_nr_connections_changed();
+}
+
+static const uint16_t packet_type_sizes[] = {
+    0, HCI_ACL_2DH1_SIZE, HCI_ACL_3DH1_SIZE, HCI_ACL_DM1_SIZE,
+    HCI_ACL_DH1_SIZE, 0, 0, 0,
+    HCI_ACL_2DH3_SIZE, HCI_ACL_3DH3_SIZE, HCI_ACL_DM3_SIZE, HCI_ACL_DH3_SIZE,
+    HCI_ACL_2DH5_SIZE, HCI_ACL_3DH5_SIZE, HCI_ACL_DM5_SIZE, HCI_ACL_DH5_SIZE
+};
+
+static uint16_t hci_acl_packet_types_for_buffer_size(uint16_t buffer_size){
+    uint16_t packet_types = 0;
+    int i;
+    for (i=0;i<16;i++){
+        if (packet_type_sizes[i] == 0) continue;
+        if (packet_type_sizes[i] <= buffer_size){
+            packet_types |= 1 << i;
+        }
+    }
+    // flip bits for "may not be used"
+    packet_types ^= 0x3306;
+    return packet_types;
+}
+
+uint16_t hci_usable_acl_packet_types(void){
+    return hci_stack.packet_types;
+}
+
+uint8_t* hci_get_outgoing_acl_packet_buffer(void){
+    // hci packet buffer is >= acl data packet length
+    return hci_stack.hci_packet_buffer;
+}
+
+uint16_t hci_max_acl_data_packet_length(){
+    return hci_stack.acl_data_packet_length;
+}
+
+// avoid huge local variables
+#ifndef EMBEDDED
+static device_name_t device_name;
+#endif
+static void event_handler(uint8_t *packet, int size){
+    bd_addr_t addr;
+    uint8_t link_type;
+    hci_con_handle_t handle;
+    hci_connection_t * conn;
+    int i;
+        
+    // printf("HCI:EVENT:%02x\n", packet[0]);
+    
+    switch (packet[0]) {
+                        
+        case HCI_EVENT_COMMAND_COMPLETE:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u\n", hci_stack.num_cmd_packets, packet[2]);
+            hci_stack.num_cmd_packets = packet[2];
+            
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_buffer_size)){
+                // from offset 5
+                // status 
+                // "The HC_ACL_Data_Packet_Length return parameter will be used to determine the size of the L2CAP segments contained in ACL Data Packets"
+                hci_stack.acl_data_packet_length = READ_BT_16(packet, 6);
+                // ignore: SCO data packet len (8)
+                hci_stack.total_num_acl_packets  = packet[9];
+                // ignore: total num SCO packets
+                if (hci_stack.state == HCI_STATE_INITIALIZING){
+                    // determine usable ACL payload size
+                    if (HCI_ACL_PAYLOAD_SIZE < hci_stack.acl_data_packet_length){
+                        hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+                    }
+                    // determine usable ACL packet types
+                    hci_stack.packet_types = hci_acl_packet_types_for_buffer_size(hci_stack.acl_data_packet_length);
+                    
+                    log_error("hci_read_buffer_size: used size %u, count %u, packet types %04x\n",
+                             hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets, hci_stack.packet_types); 
+                }
+            }
+            // Dump local address
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)) {
+                bd_addr_t addr;
+                bt_flip_addr(addr, &packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1]);
+                log_info("Local Address, Status: 0x%02x: Addr: %s\n",
+                    packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE], bd_addr_to_str(addr));
+            }
+            if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+                hci_emit_discoverable_enabled(hci_stack.discoverable);
+            }
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u\n", hci_stack.num_cmd_packets, packet[3]);
+            hci_stack.num_cmd_packets = packet[3];
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            for (i=0; i<packet[2];i++){
+                handle = READ_BT_16(packet, 3 + 2*i);
+                uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
+                conn = connection_for_handle(handle);
+                if (!conn){
+                    log_error("hci_number_completed_packet lists unused con handle %u\n", handle);
+                    continue;
+                }
+                conn->num_acl_packets_sent -= num_packets;
+                // log_info("hci_number_completed_packet %u processed for handle %u, outstanding %u\n", num_packets, handle, conn->num_acl_packets_sent);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_REQUEST:
+            bt_flip_addr(addr, &packet[2]);
+            // TODO: eval COD 8-10
+            link_type = packet[11];
+            log_info("Connection_incoming: %s, type %u\n", bd_addr_to_str(addr), link_type);
+            if (link_type == 1) { // ACL
+                conn = connection_for_address(addr);
+                if (!conn) {
+                    conn = create_connection_for_addr(addr);
+                }
+                if (!conn) {
+                    // CONNECTION REJECTED DUE TO LIMITED RESOURCES (0X0D)
+                    hci_stack.decline_reason = 0x0d;
+                    BD_ADDR_COPY(hci_stack.decline_addr, addr);
+                    break;
+                }
+                conn->state = RECEIVED_CONNECTION_REQUEST;
+                hci_run();
+            } else {
+                // SYNCHRONOUS CONNECTION LIMIT TO A DEVICE EXCEEDED (0X0A)
+                hci_stack.decline_reason = 0x0a;
+                BD_ADDR_COPY(hci_stack.decline_addr, addr);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            // Connection management
+            bt_flip_addr(addr, &packet[5]);
+            log_info("Connection_complete (status=%u) %s\n", packet[2], bd_addr_to_str(addr));
+            conn = connection_for_address(addr);
+            if (conn) {
+                if (!packet[2]){
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 3);
+                    
+                    // restart timer
+                    run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                } else {
+                    // connection failed, remove entry
+                    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                    btstack_memory_hci_connection_free( conn );
+                    
+                    // if authentication error, also delete link key
+                    if (packet[2] == 0x05) {
+                        hci_drop_link_key_for_bd_addr(&addr);
+                    }
+                }
+            }
+            break;
+
+        case HCI_EVENT_LINK_KEY_REQUEST:
+            log_info("HCI_EVENT_LINK_KEY_REQUEST\n");
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_REQUEST);
+            if (!hci_stack.remote_device_db) break;
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], HANDLE_LINK_KEY_REQUEST);
+            hci_run();
+            // request handled by hci_run() as HANDLE_LINK_KEY_REQUEST gets set
+            return;
+            
+        case HCI_EVENT_LINK_KEY_NOTIFICATION:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_NOTIFICATION);
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->put_link_key(&addr, (link_key_t *) &packet[8]);
+            // still forward event to allow dismiss of pairing dialog
+            break;
+            
+        case HCI_EVENT_PIN_CODE_REQUEST:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_PIN_CODE_REQUEST);
+            // PIN CODE REQUEST means the link key request didn't succee -> delete stored link key
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+            break;
+            
+#ifndef EMBEDDED
+        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
+            if (!hci_stack.remote_device_db) break;
+            if (packet[2]) break; // status not ok
+            bt_flip_addr(addr, &packet[3]);
+            // fix for invalid remote names - terminate on 0xff
+            for (i=0; i<248;i++){
+                if (packet[9+i] == 0xff){
+                    packet[9+i] = 0;
+                    break;
+                }
+            }
+            memset(&device_name, 0, sizeof(device_name_t));
+            strncpy((char*) device_name, (char*) &packet[9], 248);
+            hci_stack.remote_device_db->put_name(&addr, &device_name);
+            break;
+            
+        case HCI_EVENT_INQUIRY_RESULT:
+        case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
+            if (!hci_stack.remote_device_db) break;
+            // first send inq result packet
+            hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+            // then send cached remote names
+            for (i=0; i<packet[2];i++){
+                bt_flip_addr(addr, &packet[3+i*6]);
+                if (hci_stack.remote_device_db->get_name(&addr, &device_name)){
+                    hci_emit_remote_name_cached(&addr, &device_name);
+                }
+            }
+            return;
+#endif
+            
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            if (!packet[2]){
+                handle = READ_BT_16(packet, 3);
+                hci_connection_t * conn = connection_for_handle(handle);
+                if (conn) {
+                    hci_shutdown_connection(conn);
+                }
+            }
+            break;
+            
+        case HCI_EVENT_HARDWARE_ERROR:
+            if(hci_stack.control->hw_error){
+                (*hci_stack.control->hw_error)();
+            }
+            break;
+
+#ifdef HAVE_BLE
+        case HCI_EVENT_LE_META:
+            switch (packet[2]) {
+                case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+                    // Connection management
+                    bt_flip_addr(addr, &packet[8]);
+                    log_info("LE Connection_complete (status=%u) %s\n", packet[3], bd_addr_to_str(addr));
+                    // LE connections are auto-accepted, so just create a connection if there isn't one already
+                    conn = connection_for_address(addr);
+                    if (packet[3]){
+                        if (conn){
+                            // outgoing connection failed, remove entry
+                            linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                            btstack_memory_hci_connection_free( conn );
+                            
+                        }
+                        // if authentication error, also delete link key
+                        if (packet[3] == 0x05) {
+                            hci_drop_link_key_for_bd_addr(&addr);
+                        }
+                        break;
+                    }
+                    if (!conn){
+                        conn = create_connection_for_addr(addr);
+                    }
+                    if (!conn){
+                        // no memory
+                        break;
+                    }
+                    
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 4);
+                    
+                    // TODO: store - role, peer address type, conn_interval, conn_latency, supervision timeout, master clock
+
+                    // restart timer
+                    // run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    // run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+#endif            
+            
+        default:
+            break;
+    }
+
+    // handle BT initialization
+    if (hci_stack.state == HCI_STATE_INITIALIZING){
+        // handle H4 synchronization loss on restart
+        // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
+        //    hci_stack.substate = 0;
+        // }
+        // handle normal init sequence
+        if (hci_stack.substate % 2){
+            // odd: waiting for event
+            if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
+                hci_stack.substate++;
+            }
+        }
+    }
+    
+    // help with BT sleep
+    if (hci_stack.state == HCI_STATE_FALLING_ASLEEP
+        && hci_stack.substate == 1
+        && COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+        hci_stack.substate++;
+    }
+    
+    hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+    
+    // execute main loop
+    hci_run();
+}
+
+void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+/** Register HCI packet handlers */
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
+    hci_stack.packet_handler = handler;
+}
+
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db){
+    
+    // reference to use transport layer implementation
+    hci_stack.hci_transport = transport;
+    
+    // references to used control implementation
+    hci_stack.control = control;
+    
+    // reference to used config
+    hci_stack.config = config;
+    
+    // no connections yet
+    hci_stack.connections = NULL;
+    hci_stack.discoverable = 0;
+    hci_stack.connectable = 0;
+    
+    // no pending cmds
+    hci_stack.decline_reason = 0;
+    hci_stack.new_scan_enable_value = 0xff;
+    
+    // higher level handler
+    hci_stack.packet_handler = dummy_handler;
+
+    // store and open remote device db
+    hci_stack.remote_device_db = remote_device_db;
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->open();
+    }
+    
+    // max acl payload size defined in config.h
+    hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+    
+    // register packet handlers with transport
+    transport->register_packet_handler(&packet_handler);
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+void hci_close(){
+    // close remote device db
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->close();
+    }
+    while (hci_stack.connections) {
+        hci_shutdown_connection((hci_connection_t *) hci_stack.connections);
+}
+    hci_power_control(HCI_POWER_OFF);
+}
+
+// State-Module-Driver overview
+// state                    module  low-level 
+// HCI_STATE_OFF             off      close
+// HCI_STATE_INITIALIZING,   on       open
+// HCI_STATE_WORKING,        on       open
+// HCI_STATE_HALTING,        on       open
+// HCI_STATE_SLEEPING,    off/sleep   close
+// HCI_STATE_FALLING_ASLEEP  on       open
+
+static int hci_power_control_on(void){
+    
+    // power on
+    int err = 0;
+    if (hci_stack.control && hci_stack.control->on){
+        err = (*hci_stack.control->on)(hci_stack.config);
+    }
+    if (err){
+        log_error( "POWER_ON failed\n");
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    
+    // open low-level device
+    err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    return 0;
+}
+
+static void hci_power_control_off(void){
+    
+    log_info("hci_power_control_off\n");
+
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+
+    log_info("hci_power_control_off - hci_transport closed\n");
+    
+    // power off
+    if (hci_stack.control && hci_stack.control->off){
+        (*hci_stack.control->off)(hci_stack.config);
+    }
+    
+    log_info("hci_power_control_off - control closed\n");
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+static void hci_power_control_sleep(void){
+    
+    log_info("hci_power_control_sleep\n");
+    
+#if 0
+    // don't close serial port during sleep
+    
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+#endif
+    
+    // sleep mode
+    if (hci_stack.control && hci_stack.control->sleep){
+        (*hci_stack.control->sleep)(hci_stack.config);
+    }
+    
+    hci_stack.state = HCI_STATE_SLEEPING;
+}
+
+static int hci_power_control_wake(void){
+    
+    log_info("hci_power_control_wake\n");
+
+    // wake on
+    if (hci_stack.control && hci_stack.control->wake){
+        (*hci_stack.control->wake)(hci_stack.config);
+    }
+    
+#if 0
+    // open low-level device
+    int err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+#endif
+    
+    return 0;
+}
+
+
+int hci_power_control(HCI_POWER_MODE power_mode){
+    
+    log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state);
+    
+    int err = 0;
+    switch (hci_stack.state){
+            
+        case HCI_STATE_OFF:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    err = hci_power_control_on();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing (with SLEEP == OFF)
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_INITIALIZING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // no connections yet, just turn it off
+                    hci_power_control_off();
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // no connections yet, just turn it off
+                    hci_power_control_sleep();
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_WORKING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_HALTING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // set up state machine
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch (power_mode){
+                case HCI_POWER_ON:
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        break;
+                    }
+#endif
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_SLEEPING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        hci_update_scan_enable();
+                        break;
+                    }
+#endif
+                    err = hci_power_control_wake();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+    }
+
+    // create internal event
+    hci_emit_state();
+    
+    // trigger next/first action
+    hci_run();
+    
+    return 0;
+}
+
+static void hci_update_scan_enable(void){
+    // 2 = page scan, 1 = inq scan
+    hci_stack.new_scan_enable_value  = hci_stack.connectable << 1 | hci_stack.discoverable;
+    hci_run();
+}
+
+void hci_discoverable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    if (hci_stack.discoverable == enable){
+        hci_emit_discoverable_enabled(hci_stack.discoverable);
+        return;
+    }
+
+    hci_stack.discoverable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_connectable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    // don't emit event
+    if (hci_stack.connectable == enable) return;
+
+    hci_stack.connectable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_run(){
+        
+    hci_connection_t * connection;
+    linked_item_t * it;
+    
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // global/non-connection oriented commands
+    
+    // decline incoming connections
+    if (hci_stack.decline_reason){
+        uint8_t reason = hci_stack.decline_reason;
+        hci_stack.decline_reason = 0;
+        hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason);
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // send scan enable
+    if (hci_stack.new_scan_enable_value != 0xff){
+        hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value);
+        hci_stack.new_scan_enable_value = 0xff;
+    }
+    
+    // send pending HCI commands
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+        connection = (hci_connection_t *) it;
+        
+        if (connection->state == RECEIVED_CONNECTION_REQUEST){
+            log_info("sending hci_accept_connection_request\n");
+            hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
+            connection->state = ACCEPTED_CONNECTION_REQUEST;
+        }
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+        if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){
+            link_key_t link_key;
+            log_info("responding to link key request\n");
+            if ( hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){
+               hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key);
+            } else {
+               hci_send_cmd(&hci_link_key_request_negative_reply, connection->address);
+            }
+            connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
+        }
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+    switch (hci_stack.state){
+        case HCI_STATE_INITIALIZING:
+            // log_info("hci_init: substate %u\n", hci_stack.substate);
+            if (hci_stack.substate % 2) {
+                // odd: waiting for command completion
+                return;
+            }
+            switch (hci_stack.substate >> 1){
+                case 0: // RESET
+                    hci_send_cmd(&hci_reset);
+                    if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){
+                        // skip baud change
+                        hci_stack.substate = 4; // >> 1 = 2
+                    }
+                    break;
+                case 1: // SEND BAUD CHANGE
+                    hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer);
+                    hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]);
+                    break;
+                case 2: // LOCAL BAUD CHANGE
+                    hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main);
+                    hci_stack.substate += 2;
+                    // break missing here for fall through
+                    
+                case 3:
+                    // custom initialization
+                    if (hci_stack.control && hci_stack.control->next_cmd){
+                        int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer);
+                        if (valid_cmd){
+                            int size = 3 + hci_stack.hci_packet_buffer[2];
+                            hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size);
+                            hci_stack.substate = 4; // more init commands
+                            break;
+                        }
+                        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;
+                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 7:
+#ifndef EMBEDDED
+                {
+                    char hostname[30];
+                    gethostname(hostname, 30);
+                    hostname[29] = '\0';
+                    hci_send_cmd(&hci_write_local_name, hostname);
+                    break;
+                }
+                case 8:
+#ifdef USE_BLUETOOL
+                    hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone
+                    break;
+                    
+                case 9:
+#endif
+#endif
+                    // done.
+                    hci_stack.state = HCI_STATE_WORKING;
+                    hci_emit_state();
+                    break;
+                default:
+                    break;
+            }
+            hci_stack.substate++;
+            break;
+            
+        case HCI_STATE_HALTING:
+
+            log_info("HCI_STATE_HALTING\n");
+            // close all open connections
+            connection =  (hci_connection_t *) hci_stack.connections;
+            if (connection){
+                
+                // send disconnect
+                if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                
+                log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+
+                // send disconnected event right away - causes higher layer connections to get closed, too.
+                hci_shutdown_connection(connection);
+                return;
+            }
+            log_info("HCI_STATE_HALTING, calling off\n");
+            
+            // switch mode
+            hci_power_control_off();
+            
+            log_info("HCI_STATE_HALTING, emitting state\n");
+            hci_emit_state();
+            log_info("HCI_STATE_HALTING, done\n");
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch(hci_stack.substate) {
+                case 0:
+                    log_info("HCI_STATE_FALLING_ASLEEP\n");
+                    // close all open connections
+                    connection =  (hci_connection_t *) hci_stack.connections;
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't close connections, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        connection = NULL;
+                    }
+#endif
+                    if (connection){
+                        
+                        // send disconnect
+                        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+                        log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                        hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+                        
+                        // send disconnected event right away - causes higher layer connections to get closed, too.
+                        hci_shutdown_connection(connection);
+                        return;
+                    }
+                    
+                    // disable page and inquiry scan
+                    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                    
+                    log_info("HCI_STATE_HALTING, disabling inq cans\n");
+                    hci_send_cmd(&hci_write_scan_enable, hci_stack.connectable << 1); // drop inquiry scan but keep page scan
+                    
+                    // continue in next sub state
+                    hci_stack.substate++;
+                    break;
+                case 1:
+                    // wait for command complete "hci_write_scan_enable" in event_handler();
+                    break;
+                case 2:
+                    log_info("HCI_STATE_HALTING, calling sleep\n");
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't actually go to sleep, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        // SLEEP MODE reached
+                        hci_stack.state = HCI_STATE_SLEEPING; 
+                        hci_emit_state();
+                        break;
+                    }
+#endif
+                    // switch mode
+                    hci_power_control_sleep();  // changes hci_stack.state to SLEEP
+                    hci_emit_state();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+int hci_send_cmd_packet(uint8_t *packet, int size){
+    bd_addr_t addr;
+    hci_connection_t * conn;
+    // house-keeping
+    
+    // create_connection?
+    if (IS_COMMAND(packet, hci_create_connection)){
+        bt_flip_addr(addr, &packet[3]);
+        log_info("Create_connection to %s\n", bd_addr_to_str(addr));
+        conn = connection_for_address(addr);
+        if (conn) {
+            // if connection exists
+            if (conn->state == OPEN) {
+                // and OPEN, emit connection complete command
+                hci_emit_connection_complete(conn, 0);
+            }
+            //    otherwise, just ignore as it is already in the open process
+            return 0; // don't sent packet to controller
+            
+        }
+        // create connection struct and register, state = SENT_CREATE_CONNECTION
+        conn = create_connection_for_addr(addr);
+        if (!conn){
+            // notify client that alloc failed
+            hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
+            return 0; // don't sent packet to controller
+        }
+        conn->state = SENT_CREATE_CONNECTION;
+    }
+    
+    if (IS_COMMAND(packet, hci_link_key_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_link_key_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_NEGATIVE_REQUEST);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_NEGATIVE_REPLY);
+    }
+    
+    if (IS_COMMAND(packet, hci_delete_stored_link_key)){
+        if (hci_stack.remote_device_db){
+            bt_flip_addr(addr, &packet[3]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+        }
+    }
+    
+    hci_stack.num_cmd_packets--;
+    return hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
+}
+
+/**
+ * pre: numcmds >= 0 - it's allowed to send a command to the controller
+ */
+int hci_send_cmd(const hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t size = hci_create_cmd_internal(hci_stack.hci_packet_buffer, cmd, argptr);
+    va_end(argptr);
+    return hci_send_cmd_packet(hci_stack.hci_packet_buffer, size);
+}
+
+// Create various non-HCI events. 
+// TODO: generalize, use table similar to hci_create_command
+
+void hci_emit_state(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_STATE;
+    event[1] = sizeof(event) - 2;
+    event[2] = hci_stack.state;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
+    uint8_t event[13];
+    event[0] = HCI_EVENT_CONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, conn->con_handle);
+    bt_flip_addr(&event[5], conn->address);
+    event[11] = 1; // ACL connection
+    event[12] = 0; // encryption disabled
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
+    uint8_t event[6];
+    event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0; // status = OK
+    bt_store_16(event, 3, handle);
+    event[5] = reason;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn){
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_TIMEOUT_CHECK;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, conn->con_handle);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_nr_connections_changed(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_NR_CONNECTIONS_CHANGED;
+    event[1] = sizeof(event) - 2;
+    event[2] = nr_hci_connections();
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_hci_open_failed(){
+    uint8_t event[2];
+    event[0] = BTSTACK_EVENT_POWERON_FAILED;
+    event[1] = sizeof(event) - 2;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+#ifndef EMBEDDED
+void hci_emit_btstack_version() {
+    uint8_t event[6];
+    event[0] = BTSTACK_EVENT_VERSION;
+    event[1] = sizeof(event) - 2;
+    event[2] = BTSTACK_MAJOR;
+    event[3] = BTSTACK_MINOR;
+    bt_store_16(event, 4, BTSTACK_REVISION);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+#endif
+
+void hci_emit_system_bluetooth_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name){
+    uint8_t event[2+1+6+248];
+    event[0] = BTSTACK_EVENT_REMOTE_NAME_CACHED;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0;   // just to be compatible with HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
+    bt_flip_addr(&event[3], *addr);
+    memcpy(&event[9], name, 248);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_discoverable_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_DISCOVERABLE_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,359 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci.h
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <btstack/hci_cmds.h>
+#include <btstack/utils.h>
+#include "hci_transport.h"
+#include "bt_control.h"
+#include "remote_device_db.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+// packet header sizes
+#define HCI_CMD_HEADER_SIZE          3
+#define HCI_ACL_HEADER_SIZE   	     4
+#define HCI_SCO_HEADER_SIZE  	     3
+#define HCI_EVENT_HEADER_SIZE        2
+
+// packet sizes (max payload)
+#define HCI_ACL_DM1_SIZE            17
+#define HCI_ACL_DH1_SIZE            27
+#define HCI_ACL_2DH1_SIZE           54
+#define HCI_ACL_3DH1_SIZE           83
+#define HCI_ACL_DM3_SIZE           121
+#define HCI_ACL_DH3_SIZE           183
+#define HCI_ACL_DM5_SIZE           224
+#define HCI_ACL_DH5_SIZE           339
+#define HCI_ACL_2DH3_SIZE          367
+#define HCI_ACL_3DH3_SIZE          552
+#define HCI_ACL_2DH5_SIZE          679
+#define HCI_ACL_3DH5_SIZE         1021
+       
+#define HCI_EVENT_PAYLOAD_SIZE     255
+#define HCI_CMD_PAYLOAD_SIZE       255
+    
+// packet buffer sizes
+// HCI_ACL_PAYLOAD_SIZE is configurable and defined in config.h
+#define HCI_EVENT_BUFFER_SIZE      (HCI_EVENT_HEADER_SIZE + HCI_EVENT_PAYLOAD_SIZE)
+#define HCI_CMD_BUFFER_SIZE        (HCI_CMD_HEADER_SIZE   + HCI_CMD_PAYLOAD_SIZE)
+#define HCI_ACL_BUFFER_SIZE        (HCI_ACL_HEADER_SIZE   + HCI_ACL_PAYLOAD_SIZE)
+    
+// size of hci buffers, big enough for command, event, or acl packet without H4 packet type
+// @note cmd buffer is bigger than event buffer
+#if HCI_ACL_BUFFER_SIZE > HCI_CMD_BUFFER_SIZE
+#define HCI_PACKET_BUFFER_SIZE HCI_ACL_BUFFER_SIZE
+#else
+#define HCI_PACKET_BUFFER_SIZE HCI_CMD_BUFFER_SIZE
+#endif
+    
+// OGFs
+#define OGF_LINK_CONTROL          0x01
+#define OGF_LINK_POLICY           0x02
+#define OGF_CONTROLLER_BASEBAND   0x03
+#define OGF_INFORMATIONAL_PARAMETERS 0x04
+#define OGF_LE_CONTROLLER 0x08
+#define OGF_BTSTACK 0x3d
+#define OGF_VENDOR  0x3f
+
+// cmds for BTstack 
+// get state: @returns HCI_STATE
+#define BTSTACK_GET_STATE                                  0x01
+
+// set power mode: @param HCI_POWER_MODE
+#define BTSTACK_SET_POWER_MODE                             0x02
+
+// set capture mode: @param on
+#define BTSTACK_SET_ACL_CAPTURE_MODE                       0x03
+
+// get BTstack version
+#define BTSTACK_GET_VERSION                                0x04
+
+// get system Bluetooth state
+#define BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED               0x05
+
+// set system Bluetooth state
+#define BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED               0x06
+
+// enable inquiry scan for this client
+#define BTSTACK_SET_DISCOVERABLE                           0x07
+
+// set global Bluetooth state
+#define BTSTACK_SET_BLUETOOTH_ENABLED                      0x08
+
+// create l2cap channel: @param bd_addr(48), psm (16)
+#define L2CAP_CREATE_CHANNEL                               0x20
+
+// disconnect l2cap disconnect, @param channel(16), reason(8)
+#define L2CAP_DISCONNECT                                   0x21
+
+// register l2cap service: @param psm(16), mtu (16)
+#define L2CAP_REGISTER_SERVICE                             0x22
+
+// unregister l2cap disconnect, @param psm(16)
+#define L2CAP_UNREGISTER_SERVICE                           0x23
+
+// accept connection @param bd_addr(48), dest cid (16)
+#define L2CAP_ACCEPT_CONNECTION                            0x24
+
+// decline l2cap disconnect,@param bd_addr(48), dest cid (16), reason(8)
+#define L2CAP_DECLINE_CONNECTION                           0x25
+
+// create l2cap channel: @param bd_addr(48), psm (16), mtu (16)
+#define L2CAP_CREATE_CHANNEL_MTU                           0x26
+
+// register SDP Service Record: service record (size)
+#define SDP_REGISTER_SERVICE_RECORD                        0x30
+
+// unregister SDP Service Record
+#define SDP_UNREGISTER_SERVICE_RECORD                      0x31
+
+// RFCOMM "HCI" Commands
+#define RFCOMM_CREATE_CHANNEL       0x40
+#define RFCOMM_DISCONNECT			0x41
+#define RFCOMM_REGISTER_SERVICE     0x42
+#define RFCOMM_UNREGISTER_SERVICE   0x43
+#define RFCOMM_ACCEPT_CONNECTION    0x44
+#define RFCOMM_DECLINE_CONNECTION   0x45
+#define RFCOMM_PERSISTENT_CHANNEL   0x46
+#define RFCOMM_CREATE_CHANNEL_WITH_CREDITS   0x47
+#define RFCOMM_REGISTER_SERVICE_WITH_CREDITS 0x48
+#define RFCOMM_GRANT_CREDITS                 0x49
+    
+// 
+#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_OPENED                     0x50
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_CLOSED                     0x51
+
+// data: event(8), nr_connections(8)
+#define DAEMON_NR_CONNECTIONS_CHANGED                      0x52
+
+// data: event(8)
+#define DAEMON_EVENT_NEW_RFCOMM_CREDITS                    0x53
+
+// data: event()
+#define DAEMON_EVENT_HCI_PACKET_SENT                       0x54
+    
+/**
+ * Connection State 
+ */
+typedef enum {
+    AUTH_FLAGS_NONE                = 0x00,
+    RECV_LINK_KEY_REQUEST          = 0x01,
+    HANDLE_LINK_KEY_REQUEST        = 0x02,
+    SENT_LINK_KEY_REPLY            = 0x04,
+    SENT_LINK_KEY_NEGATIVE_REQUEST = 0x08,
+    RECV_LINK_KEY_NOTIFICATION     = 0x10,
+    RECV_PIN_CODE_REQUEST          = 0x20,
+    SENT_PIN_CODE_REPLY            = 0x40, 
+    SENT_PIN_CODE_NEGATIVE_REPLY   = 0x80 
+} hci_authentication_flags_t;
+
+typedef enum {
+    SENT_CREATE_CONNECTION = 1,
+    RECEIVED_CONNECTION_REQUEST,
+    ACCEPTED_CONNECTION_REQUEST,
+    REJECTED_CONNECTION_REQUEST,
+    OPEN,
+    SENT_DISCONNECT
+} CONNECTION_STATE;
+
+typedef enum {
+    BLUETOOTH_OFF = 1,
+    BLUETOOTH_ON,
+    BLUETOOTH_ACTIVE
+} BLUETOOTH_STATE;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // remote side
+    bd_addr_t address;
+    
+    // module handle
+    hci_con_handle_t con_handle;
+
+    // state
+    CONNECTION_STATE state;
+    
+    // errands
+    hci_authentication_flags_t authentication_flags;
+
+    timer_source_t timeout;
+    
+#ifdef HAVE_TIME
+    // timer
+    struct timeval timestamp;
+#endif
+#ifdef HAVE_TICK
+    uint32_t timestamp; // timeout in system ticks
+#endif
+    
+    // ACL packet recombination - ACL Header + ACL payload
+    uint8_t  acl_recombination_buffer[4 + HCI_ACL_BUFFER_SIZE];
+    uint16_t acl_recombination_pos;
+    uint16_t acl_recombination_length;
+    
+    // number ACL packets sent to controller
+    uint8_t num_acl_packets_sent;
+    
+} hci_connection_t;
+
+/**
+ * main data structure
+ */
+typedef struct {
+    // transport component with configuration
+    hci_transport_t  * hci_transport;
+    void             * config;
+    
+    // hardware power controller
+    bt_control_t     * control;
+    
+    // list of existing baseband connections
+    linked_list_t     connections;
+
+    // single buffer for HCI Command assembly
+    uint8_t          hci_packet_buffer[HCI_PACKET_BUFFER_SIZE]; // opcode (16), len(8)
+    
+    /* host to controller flow control */
+    uint8_t  num_cmd_packets;
+    // uint8_t  total_num_cmd_packets;
+    uint8_t  total_num_acl_packets;
+    uint16_t acl_data_packet_length;
+
+    // usable packet types given acl_data_packet_length and HCI_ACL_BUFFER_SIZE
+    uint16_t packet_types;
+    
+    /* callback to L2CAP layer */
+    void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+    /* remote device db */
+    remote_device_db_t const*remote_device_db;
+    
+    /* hci state machine */
+    HCI_STATE state;
+    uint8_t   substate;
+    uint8_t   cmds_ready;
+    
+    uint8_t   discoverable;
+    uint8_t   connectable;
+    
+    /* buffer for scan enable cmd - 0xff no change */
+    uint8_t   new_scan_enable_value;
+    
+    // buffer for single connection decline
+    uint8_t   decline_reason;
+    bd_addr_t decline_addr;
+    
+} hci_stack_t;
+
+// create and send hci command packets based on a template and a list of parameters
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...);
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr);
+
+// set up HCI
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db);
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+void hci_close(void);
+
+// power and inquriy scan control
+int  hci_power_control(HCI_POWER_MODE mode);
+void hci_discoverable_control(uint8_t enable);
+void hci_connectable_control(uint8_t enable);
+
+/**
+ * run the hci control loop once
+ */
+void hci_run(void);
+
+// create and send hci command packets based on a template and a list of parameters
+int hci_send_cmd(const hci_cmd_t *cmd, ...);
+
+// send complete CMD packet
+int hci_send_cmd_packet(uint8_t *packet, int size);
+
+// send ACL packet
+int hci_send_acl_packet(uint8_t *packet, int size);
+
+// non-blocking UART driver needs
+int hci_can_send_packet_now(uint8_t packet_type);
+    
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle);
+uint8_t  hci_number_outgoing_packets(hci_con_handle_t handle);
+uint8_t  hci_number_free_acl_slots(void);
+int      hci_authentication_active_for_handle(hci_con_handle_t handle);
+void     hci_drop_link_key_for_bd_addr(bd_addr_t *addr);
+uint16_t hci_max_acl_data_packet_length(void);
+uint16_t hci_usable_acl_packet_types(void);
+uint8_t* hci_get_outgoing_acl_packet_buffer(void);
+
+// 
+void hci_emit_state(void);
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status);
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn);
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason);
+void hci_emit_nr_connections_changed(void);
+void hci_emit_hci_open_failed(void);
+void hci_emit_btstack_version(void);
+void hci_emit_system_bluetooth_enabled(uint8_t enabled);
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name);
+void hci_emit_discoverable_enabled(uint8_t enabled);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_cmds.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,679 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci_cmds.c
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include <btstack/hci_cmds.h>
+
+#include <string.h>
+
+#include <btstack/sdp_util.h>
+#include "config.h"
+#include "hci.h"
+
+// calculate combined ogf/ocf value
+#define OPCODE(ogf, ocf) (ocf | ogf << 10)
+
+/**
+ * construct HCI Command based on template
+ *
+ * Format:
+ *   1,2,3,4: one to four byte value
+ *   H: HCI connection handle
+ *   B: Bluetooth Baseband Address (BD_ADDR)
+ *   E: Extended Inquiry Result
+ *   N: Name up to 248 chars, \0 terminated
+ *   P: 16 byte Pairing code
+ *   S: Service Record (Data Element Sequence)
+ */
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr){
+    
+    hci_cmd_buffer[0] = cmd->opcode & 0xff;
+    hci_cmd_buffer[1] = cmd->opcode >> 8;
+    int pos = 3;
+    
+    const char *format = cmd->format;
+    uint16_t word;
+    uint32_t longword;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+            case 'H': // hci_handle
+                word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                hci_cmd_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } else if (*format == 'H') {
+                    // TODO implement opaque client connection handles
+                    //      pass module handle for now
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } 
+                break;
+            case '3':
+            case '4':
+                longword = va_arg(argptr, uint32_t);
+                // longword = va_arg(argptr, int);
+                hci_cmd_buffer[pos++] = longword;
+                hci_cmd_buffer[pos++] = longword >> 8;
+                hci_cmd_buffer[pos++] = longword >> 16;
+                if (*format == '4'){
+                    hci_cmd_buffer[pos++] = longword >> 24;
+                }
+                break;
+            case 'B': // bt-addr
+                ptr = va_arg(argptr, uint8_t *);
+                hci_cmd_buffer[pos++] = ptr[5];
+                hci_cmd_buffer[pos++] = ptr[4];
+                hci_cmd_buffer[pos++] = ptr[3];
+                hci_cmd_buffer[pos++] = ptr[2];
+                hci_cmd_buffer[pos++] = ptr[1];
+                hci_cmd_buffer[pos++] = ptr[0];
+                break;
+            case 'E': // Extended Inquiry Information 240 octets
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 240);
+                pos += 240;
+                break;
+            case 'N': { // UTF-8 string, null terminated
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = strlen((const char*) ptr);
+                if (len > 248) {
+                    len = 248;
+                }
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                if (len < 248) {
+                    // fill remaining space with zeroes
+                    memset(&hci_cmd_buffer[pos+len], 0, 248-len);
+                }
+                pos += 248;
+                break;
+            }
+            case 'P': // 16 byte PIN code or link key
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 16);
+                pos += 16;
+                break;
+#ifdef HAVE_BLE
+            case 'A': // 31 bytes advertising data
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 31);
+                pos += 31;
+                break;
+#endif
+#ifdef HAVE_SDP
+            case 'S': { // Service Record (Data Element Sequence)
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = de_get_len(ptr);
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                pos += len;
+                break;
+            }
+#endif
+            default:
+                break;
+        }
+        format++;
+    };
+    hci_cmd_buffer[2] = pos - 3;
+    return pos;
+}
+
+/**
+ * construct HCI Command based on template
+ *
+ * mainly calls hci_create_cmd_internal
+ */
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t len = hci_create_cmd_internal(hci_cmd_buffer, cmd, argptr);
+    va_end(argptr);
+    return len;
+}
+
+
+/**
+ *  Link Control Commands 
+ */
+const hci_cmd_t hci_inquiry = {
+OPCODE(OGF_LINK_CONTROL, 0x01), "311"
+// LAP, Inquiry length, Num_responses
+};
+const hci_cmd_t hci_inquiry_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x02), ""
+// no params
+};
+const hci_cmd_t hci_create_connection = {
+OPCODE(OGF_LINK_CONTROL, 0x05), "B21121"
+// BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+};
+const hci_cmd_t hci_disconnect = {
+OPCODE(OGF_LINK_CONTROL, 0x06), "H1"
+// Handle, Reason: 0x05, 0x13-0x15, 0x1a, 0x29
+// see Errors Codes in BT Spec Part D
+};
+const hci_cmd_t hci_create_connection_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x08), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_accept_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x09), "B1"
+// BD_ADDR, Role: become master, stay slave
+};
+const hci_cmd_t hci_reject_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x0a), "B1"
+// BD_ADDR, reason e.g. CONNECTION REJECTED DUE TO LIMITED RESOURCES (0x0d)
+};
+const hci_cmd_t hci_link_key_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0b), "BP"
+// BD_ADDR, LINK_KEY
+};
+const hci_cmd_t hci_link_key_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0c), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_pin_code_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0d), "B1P"
+// BD_ADDR, pin length, PIN: c-string
+};
+const hci_cmd_t hci_pin_code_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0e), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_authentication_requested = {
+OPCODE(OGF_LINK_CONTROL, 0x11), "H"
+// Handle
+};
+const hci_cmd_t hci_set_connection_encryption = {
+OPCODE(OGF_LINK_CONTROL, 0x13), "H1"
+// Handle, Encryption_Enable
+};
+const hci_cmd_t hci_change_connection_link_key = {
+OPCODE(OGF_LINK_CONTROL, 0x15), "H"
+// Handle
+};
+const hci_cmd_t hci_remote_name_request = {
+OPCODE(OGF_LINK_CONTROL, 0x19), "B112"
+// BD_ADDR, Page_Scan_Repetition_Mode, Reserved, Clock_Offset
+};
+const hci_cmd_t hci_remote_name_request_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x1A), "B"
+// BD_ADDR
+};
+
+/**
+ *  Link Policy Commands 
+ */
+const hci_cmd_t hci_sniff_mode = {
+OPCODE(OGF_LINK_POLICY, 0x03), "H2222"
+// handle, Sniff_Max_Interval, Sniff_Min_Interval, Sniff_Attempt, Sniff_Timeout:
+};
+const hci_cmd_t hci_qos_setup = {
+OPCODE(OGF_LINK_POLICY, 0x07), "H114444"
+// handle, flags, service_type, token rate (bytes/s), peak bandwith (bytes/s),
+// latency (us), delay_variation (us)
+};
+const hci_cmd_t hci_role_discovery = {
+OPCODE(OGF_LINK_POLICY, 0x09), "H"
+// handle
+};
+const hci_cmd_t hci_switch_role_command= {
+OPCODE(OGF_LINK_POLICY, 0x0b), "B1"
+// BD_ADDR, role: {0=master,1=slave}
+};
+const hci_cmd_t hci_read_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0c), "H"
+// handle 
+};
+const hci_cmd_t hci_write_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0d), "H2"
+// handle, settings
+};
+
+/**
+ *  Controller & Baseband Commands 
+ */
+const hci_cmd_t hci_set_event_mask = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x01), "44"
+// event_mask lower 4 octets, higher 4 bytes
+};
+const hci_cmd_t hci_reset = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_delete_stored_link_key = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x12), "B1"
+// BD_ADDR, Delete_All_Flag
+};
+const hci_cmd_t hci_write_local_name = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x13), "N"
+// Local name (UTF-8, Null Terminated, max 248 octets)
+};
+const hci_cmd_t hci_write_page_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x18), "2"
+// Page_Timeout * 0.625 ms
+};
+const hci_cmd_t hci_write_scan_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x1A), "1"
+// Scan_enable: no, inq, page, inq+page
+};
+const hci_cmd_t hci_write_authentication_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x20), "1"
+// Authentication_Enable
+};
+const hci_cmd_t hci_write_class_of_device = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x24), "3"
+// Class of Device
+};
+const hci_cmd_t hci_read_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x29), ""
+};
+const hci_cmd_t hci_write_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x2a), "1"
+// Num broadcast retransmissions (e.g. 0 for a single broadcast)
+};
+const hci_cmd_t hci_host_buffer_size = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122"
+// Host_ACL_Data_Packet_Length:, Host_Synchronous_Data_Packet_Length:, Host_Total_Num_ACL_Data_Packets:, Host_Total_Num_Synchronous_Data_Packets:
+};
+const hci_cmd_t hci_read_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x36), "H"
+// handle
+};
+const hci_cmd_t hci_write_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x37), "H2"
+// handle, Range for N: 0x0001 Ð 0xFFFF Time (Range: 0.625ms Ð 40.9 sec)
+};
+const hci_cmd_t hci_write_inquiry_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x45), "1"
+// Inquiry mode: 0x00 = standard, 0x01 = with RSSI, 0x02 = extended
+};
+const hci_cmd_t hci_write_extended_inquiry_response = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x52), "1E"
+// FEC_Required, Exstended Inquiry Response
+};
+const hci_cmd_t hci_write_simple_pairing_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x56), "1"
+// mode: 0 = off, 1 = on
+};
+const hci_cmd_t hci_read_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6c), ""
+// params: none
+// return: status, le supported host, simultaneous le host
+};
+const hci_cmd_t hci_write_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6d), "11"
+// param: le supported host, simultaneous le host
+// return: status
+};
+
+/**
+ * Informational Parameters
+ */
+const hci_cmd_t hci_read_local_supported_features = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_read_buffer_size = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x05), ""
+// no params
+};
+const hci_cmd_t hci_read_bd_addr = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x09), ""
+// no params
+};
+
+#ifdef HAVE_BLE
+/**
+ * Low Energy Commands
+ */
+const hci_cmd_t hci_le_set_event_mask = {
+OPCODE(OGF_LE_CONTROLLER, 0x01), "44"
+// params: event_mask lower 4 octets, higher 4 bytes
+// return: status
+};
+const hci_cmd_t hci_le_read_buffer_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x02), ""
+// params: none
+// return: status, le acl data packet len (16), total num le acl data packets(8)
+};
+const hci_cmd_t hci_le_read_supported_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x03), ""
+// params: none
+// return: LE_Features See [Vol 6] Part B, Section 4.6
+};
+const hci_cmd_t hci_le_set_random_address = {
+OPCODE(OGF_LE_CONTROLLER, 0x05), "B"
+// params: random device address
+// return: status
+};
+const hci_cmd_t hci_le_set_advertising_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x06), "22111B11"
+// param: min advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: max advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: advertising type (enum from 0): ADV_IND, ADC_DIRECT_IND, ADV_SCAN_IND, ADV_NONCONN_IND
+// param: own address type (enum from 0): public device address, random device address
+// param: direct address type (enum from 0): public device address, random device address
+// param: direct address - public or random address of device to be connecteed
+// param: advertising channel map (flags): chan_37(1), chan_38(2), chan_39(4)
+// param: advertising filter policy (enum from 0): scan any conn any, scan whitelist, con any, scan any conn whitelist, scan whitelist, con whitelist
+// return: status
+};
+const hci_cmd_t hci_le_read_advertising_channel_tx_power = {
+OPCODE(OGF_LE_CONTROLLER, 0x07), ""
+// params: none
+// return: status, level [-20,10] signed int (8), units dBm
+};
+const hci_cmd_t hci_le_set_advertising_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x08), "1A"
+// param: advertising data len
+// param: advertising data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_response_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x09), "1A"
+// param: scan response data len
+// param: scan response data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_advertise_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0a), "1"
+// params: avertise enable: off (0), on (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x0b), "12211"
+// param: le scan type: passive (0), active (1)
+// param: le scan interval [0x0004,0x4000], unit: 0.625 msec
+// param: le scan window   [0x0004,0x4000], unit: 0.625 msec
+// param: own address type: public (0), random (1)
+// param: scanning filter policy: any (0), only whitelist (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0c), "11"
+// param: le scan enable:  disabled (0), enabled (1)
+// param: filter duplices: disabled (0), enabled (1)
+// return: status
+};
+const hci_cmd_t hci_le_create_connection= {
+OPCODE(OGF_LE_CONTROLLER, 0x0d), "2211B1222222"
+// param: le scan interval, [0x0004, 0x4000], unit: 0.625 msec
+// param: le scan window, [0x0004, 0x4000], unit: 0.625 msec
+// param: initiator filter policy: peer address type + peer address (0), whitelist (1)
+// param: peer address type: public (0), random (1)
+// param: peer address
+// param: own address type: public (0), random (1)
+// param: conn interval min, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn latency, number of connection events [0x0000, 0x01f4]
+// param: supervision timeout, [0x000a, 0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000, 0xffff], unit: 0.625 msec
+// return: none -> le create connection complete event
+};
+const hci_cmd_t hci_le_create_connection_cancel = {
+OPCODE(OGF_LE_CONTROLLER, 0x0e), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_read_white_list_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x0f), ""
+// params: none
+// return: status, number of entries in controller whitelist
+};
+const hci_cmd_t hci_le_clear_white_list = {
+OPCODE(OGF_LE_CONTROLLER, 0x10), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_add_device_to_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x11), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_remove_device_from_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x12), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_connection_update = {
+OPCODE(OGF_LE_CONTROLLER, 0x13), "H222222"
+// param: conn handle
+// param: conn interval min, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn latency, [0x0000,0x03e8], number of connection events
+// param: supervision timeout, [0x000a,0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000,0xffff], unit: 0.625 msec
+// param: maximum CE length, [0x0000,0xffff], unit: 0.625 msec
+// return: none -> le connection update complete event
+};
+const hci_cmd_t hci_le_set_host_channel_classification = {
+OPCODE(OGF_LE_CONTROLLER, 0x14), "41"
+// param: channel map 37 bit, split into first 32 and higher 5 bits
+// return: status
+};
+const hci_cmd_t hci_le_read_channel_map = {
+OPCODE(OGF_LE_CONTROLLER, 0x15), "H"
+// params: connection handle
+// return: status, connection handle, channel map (5 bytes, 37 used)
+};
+const hci_cmd_t hci_le_read_remote_used_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x16), "H"
+// params: connection handle
+// return: none -> le read remote used features complete event
+};
+const hci_cmd_t hci_le_encrypt = {
+OPCODE(OGF_LE_CONTROLLER, 0x17), "PP"
+// param: key (128) for AES-128
+// param: plain text (128) 
+// return: status, encrypted data (128)
+};
+const hci_cmd_t hci_le_rand = {
+OPCODE(OGF_LE_CONTROLLER, 0x18), ""
+// params: none
+// return: status, random number (64)
+};
+const hci_cmd_t hci_le_start_encryption = {
+OPCODE(OGF_LE_CONTROLLER, 0x19), "H442P"
+// param: connection handle
+// param: 64 bit random number lower  32 bit
+// param: 64 bit random number higher 32 bit
+// param: encryption diversifier (16)
+// param: long term key (128)
+// return: none -> encryption changed or encryption key refresh complete event
+};
+const hci_cmd_t hci_le_long_term_key_request_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1a), "HP"
+// param: connection handle
+// param: long term key (128)
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_long_term_key_negative_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1b), "H"
+// param: connection handle
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_read_supported_states = {
+OPCODE(OGF_LE_CONTROLLER, 0x1c), "H"
+// param: none
+// return: status, LE states (64)
+};
+const hci_cmd_t hci_le_receiver_test = {
+OPCODE(OGF_LE_CONTROLLER, 0x1d), "1"
+// param: rx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+// return: status
+};
+const hci_cmd_t hci_le_transmitter_test = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1e), "111"
+    // param: tx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+    // param: lengh of test payload [0x00,0x25]
+    // param: packet payload [0,7] different patterns
+    // return: status
+};
+const hci_cmd_t hci_le_test_end = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1f), "1"
+    // params: none
+    // return: status, number of packets (8)
+};
+#endif
+
+// BTstack commands
+const hci_cmd_t btstack_get_state = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_STATE), ""
+// no params -> 
+};
+
+const hci_cmd_t btstack_set_power_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_POWER_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_set_acl_capture_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_ACL_CAPTURE_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_get_version = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_VERSION), ""
+};
+
+const hci_cmd_t btstack_get_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED), ""
+};
+
+const hci_cmd_t btstack_set_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t btstack_set_discoverable = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_DISCOVERABLE), "1"
+};
+
+const hci_cmd_t btstack_set_bluetooth_enabled = {
+// only used by btstack config
+OPCODE(OGF_BTSTACK, BTSTACK_SET_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t l2cap_create_channel = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL), "B2"
+// @param bd_addr(48), psm (16)
+};
+const hci_cmd_t l2cap_create_channel_mtu = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL_MTU), "B22"
+// @param bd_addr(48), psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_disconnect = {
+OPCODE(OGF_BTSTACK, L2CAP_DISCONNECT), "21"
+// @param channel(16), reason(8)
+};
+const hci_cmd_t l2cap_register_service = {
+OPCODE(OGF_BTSTACK, L2CAP_REGISTER_SERVICE), "22"
+// @param psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_unregister_service = {
+OPCODE(OGF_BTSTACK, L2CAP_UNREGISTER_SERVICE), "2"
+// @param psm (16)
+};
+const hci_cmd_t l2cap_accept_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_ACCEPT_CONNECTION), "2"
+// @param source cid (16)
+};
+const hci_cmd_t l2cap_decline_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_DECLINE_CONNECTION), "21"
+// @param source cid (16), reason(8)
+};
+const hci_cmd_t sdp_register_service_record = {
+OPCODE(OGF_BTSTACK, SDP_REGISTER_SERVICE_RECORD), "S"
+// @param service record handle (DES)
+};
+const hci_cmd_t sdp_unregister_service_record = {
+OPCODE(OGF_BTSTACK, SDP_UNREGISTER_SERVICE_RECORD), "4"
+// @param service record handle (32)
+};
+
+// create rfcomm channel: @param bd_addr(48), channel (8)
+const hci_cmd_t rfcomm_create_channel = {
+	OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL), "B1"
+};
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+const hci_cmd_t rfcomm_create_channel_with_initial_credits = {
+	OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL_WITH_CREDITS), "B121"
+};
+// grant credits: @param rfcomm_cid(16), credits (8)
+const hci_cmd_t rfcomm_grants_credits= {
+	OPCODE(OGF_BTSTACK, RFCOMM_GRANT_CREDITS), "21"
+};
+// disconnect rfcomm disconnect, @param rfcomm_cid(16), reason(8)
+const  hci_cmd_t rfcomm_disconnect = {
+	OPCODE(OGF_BTSTACK, RFCOMM_DISCONNECT), "21"
+};
+
+// register rfcomm service: @param channel(8), mtu (16)
+const hci_cmd_t rfcomm_register_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "12"
+};
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+const hci_cmd_t rfcomm_register_service_with_initial_credits = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE_WITH_CREDITS), "121"
+};
+
+// unregister rfcomm service, @param service_channel(16)
+const hci_cmd_t rfcomm_unregister_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_UNREGISTER_SERVICE), "2"
+};
+// accept connection @param source cid (16)
+const hci_cmd_t rfcomm_accept_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_ACCEPT_CONNECTION), "2"
+};
+// decline connection @param source cid (16)
+const hci_cmd_t rfcomm_decline_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_DECLINE_CONNECTION), "21"
+};
+// request persisten rfcomm channel number for named service
+const hci_cmd_t rfcomm_persistent_channel_for_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_PERSISTENT_CHANNEL), "N"
+};
+
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_dump.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,239 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci_dump.c
+ *
+ *  Dump HCI trace in various formats:
+ *
+ *  - BlueZ's hcidump format
+ *  - Apple's PacketLogger
+ *  - stdout hexdump
+ *
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#include "config.h"
+
+#include "hci_dump.h"
+#include "hci.h"
+#include "hci_transport.h"
+#include <btstack/hci_cmds.h>
+
+#ifndef EMBEDDED
+#include <fcntl.h>        // open
+#include <arpa/inet.h>    // hton..
+#include <unistd.h>       // write 
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>     // for timestamps
+#include <sys/stat.h>     // for mode flags
+#include <stdarg.h>       // for va_list
+#endif
+
+// BLUEZ hcidump
+typedef struct {
+	uint16_t	len;
+	uint8_t		in;
+	uint8_t		pad;
+	uint32_t	ts_sec;
+	uint32_t	ts_usec;
+    uint8_t     packet_type;
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif 
+hcidump_hdr;
+
+// APPLE PacketLogger
+typedef struct {
+	uint32_t	len;
+	uint32_t	ts_sec;
+	uint32_t	ts_usec;
+	uint8_t		type;   // 0xfc for note
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif
+pktlog_hdr;
+
+#ifndef EMBEDDED
+static int dump_file = -1;
+static int dump_format;
+static hcidump_hdr header_bluez;
+static pktlog_hdr  header_packetlogger;
+static char time_string[40];
+static int  max_nr_packets = -1;
+static int  nr_packets = 0;
+static char log_message_buffer[256];
+#endif
+
+void hci_dump_open(char *filename, hci_dump_format_t format){
+#ifndef EMBEDDED
+    dump_format = format;
+    if (dump_format == HCI_DUMP_STDOUT) {
+        dump_file = fileno(stdout);
+    } else {
+        dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    }
+#endif
+}
+
+#ifndef EMBEDDED
+void hci_dump_set_max_packets(int packets){
+    max_nr_packets = packets;
+}
+#endif
+
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
+#ifndef EMBEDDED
+
+    if (dump_file < 0) return; // not activated yet
+
+    // don't grow bigger than max_nr_packets
+    if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
+        if (nr_packets >= max_nr_packets){
+            lseek(dump_file, 0, SEEK_SET);
+            ftruncate(dump_file, 0);
+            nr_packets = 0;
+        }
+        nr_packets++;
+    }
+    
+    // get time
+    struct timeval curr_time;
+    struct tm* ptm;
+    gettimeofday(&curr_time, NULL);
+    
+    switch (dump_format){
+        case HCI_DUMP_STDOUT: {
+            /* Obtain the time of day, and convert it to a tm struct. */
+            ptm = localtime (&curr_time.tv_sec);
+            /* Format the date and time, down to a single second. */
+            strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
+            /* Compute milliseconds from microseconds. */
+            uint16_t milliseconds = curr_time.tv_usec / 1000;
+            /* Print the formatted time, in seconds, followed by a decimal point
+             and the milliseconds. */
+            printf ("%s.%03u] ", time_string, milliseconds);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    printf("CMD => ");
+                    break;
+                case HCI_EVENT_PACKET:
+                    printf("EVT <= ");
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        printf("ACL <= ");
+                    } else {
+                        printf("ACL => ");
+                    }
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    // assume buffer is big enough
+                    packet[len] = 0;
+                    printf("LOG -- %s\n", (char*) packet);
+                    return;
+                default:
+                    return;
+            }
+            hexdump(packet, len);
+            break;
+        }
+            
+        case HCI_DUMP_BLUEZ:
+            bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
+            header_bluez.in  = in;
+            header_bluez.pad = 0;
+            bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
+            bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
+            header_bluez.packet_type = packet_type;
+            write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        case HCI_DUMP_PACKETLOGGER:
+            header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
+            header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
+            header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    header_packetlogger.type = 0x00;
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        header_packetlogger.type = 0x03;
+                    } else {
+                        header_packetlogger.type = 0x02;
+                    }
+                    break;
+                case HCI_EVENT_PACKET:
+                    header_packetlogger.type = 0x01;
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    header_packetlogger.type = 0xfc;
+                    break;
+                default:
+                    return;
+            }
+            write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        default:
+            break;
+    }
+#endif
+}
+
+void hci_dump_log(const char * format, ...){
+#ifndef EMBEDDED
+    va_list argptr;
+    va_start(argptr, format);
+    int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
+    hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
+    va_end(argptr);
+#endif    
+}
+
+void hci_dump_close(){
+#ifndef EMBEDDED
+    close(dump_file);
+    dump_file = -1;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_dump.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,59 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci_dump.h
+ *
+ *  Dump HCI trace as BlueZ's hcidump format, Apple's PacketLogger, or stdout
+ * 
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    HCI_DUMP_BLUEZ = 0,
+    HCI_DUMP_PACKETLOGGER,
+    HCI_DUMP_STDOUT
+} hci_dump_format_t;
+
+void hci_dump_open(char *filename, hci_dump_format_t format);
+void hci_dump_set_max_packets(int packets); // -1 for unlimited
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
+void hci_dump_log(const char * format, ...);
+void hci_dump_close(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_transport.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,88 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci_transport.h
+ *
+ *  HCI Transport API -- allows BT Daemon to use different transport protcols 
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <btstack/run_loop.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+/* HCI packet types */
+typedef struct {
+    int    (*open)(void *transport_config);
+    int    (*close)(void *transport_config);
+    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);
+    void   (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+    const char * (*get_transport_name)(void);
+    // custom extension for UART transport implementations
+    int    (*set_baudrate)(uint32_t baudrate);
+    // support async transport layers, e.g. IRQ driven without buffers
+    int    (*can_send_packet_now)(uint8_t packet_type);
+} hci_transport_t;
+
+typedef struct {
+    const char *device_name;
+    uint32_t   baudrate_init; // initial baud rate
+    uint32_t   baudrate_main; // = 0: same as initial baudrate
+    int   flowcontrol; // 
+} hci_uart_config_t;
+
+
+// inline various hci_transport_X.h files
+extern hci_transport_t * hci_transport_h4_instance(void);
+extern hci_transport_t * hci_transport_h4_dma_instance(void);
+extern hci_transport_t * hci_transport_h4_iphone_instance(void);
+extern hci_transport_t * hci_transport_h5_instance(void);
+extern hci_transport_t * hci_transport_usb_instance(void);
+
+// support for "enforece wake device" in h4 - used by iOS power management
+extern void hci_transport_h4_iphone_set_enforce_wake_device(char *path);
+    
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_transport_usb.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  hci_transport_usb.cpp
+ *
+ *  HCI Transport API implementation for USB
+ *
+ *  Created by Matthias Ringwald on 7/5/09.
+ */
+
+// delock bt class 2 - csr
+// 0a12:0001 (bus 27, device 2)
+
+// Interface Number - Alternate Setting - suggested Endpoint Address - Endpoint Type - Suggested Max Packet Size 
+// HCI Commands 0 0 0x00 Control 8/16/32/64 
+// HCI Events   0 0 0x81 Interrupt (IN) 16 
+// ACL Data     0 0 0x82 Bulk (IN) 32/64 
+// ACL Data     0 0 0x02 Bulk (OUT) 32/64 
+
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "debug.h"
+#include "hci.h"
+#include "hci_transport.h"
+#include "hci_dump.h"
+#include "usbbt.h"
+// prototypes
+static int usb_close(void *transport_config);
+    
+enum {
+    LIB_USB_CLOSED = 0,
+    LIB_USB_OPENED,
+    LIB_USB_DEVICE_OPENDED,
+    LIB_USB_KERNEL_DETACHED,
+    LIB_USB_INTERFACE_CLAIMED,
+    LIB_USB_TRANSFERS_ALLOCATED
+} libusb_state = LIB_USB_CLOSED;
+
+// single instance
+static hci_transport_t * hci_transport_usb = NULL;
+static usbbt* bt = NULL;
+static int usb_process_ds(struct data_source *ds) {
+    if (bt) {
+        bt->poll();
+    }
+    return 0;
+}
+
+static int usb_open(void *transport_config){
+    log_info("usb_open\n");
+    data_source_t *ds = (data_source_t*)malloc(sizeof(data_source_t));
+    ds->process = usb_process_ds;
+    run_loop_add_data_source(ds);
+    return 0;
+}
+static int usb_close(void *transport_config){
+
+    return 0;
+}
+
+static int usb_send_packet(uint8_t packet_type, uint8_t * packet, int size){
+    //log_info("usb_send_packet\n");
+    if (bt) {
+        bt->send_packet(packet_type, packet, size);
+    }
+    return 0;
+}
+
+static void usb_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
+    log_info("registering packet handler\n");
+    if (bt) {
+        bt->setOnPacket(handler);
+    }
+}
+
+static const char * usb_get_transport_name(void){
+    return "USB";
+}
+
+// get usb singleton
+hci_transport_t * hci_transport_usb_instance() {
+    if (!bt) {
+        bt = new usbbt;
+        bt->setup();
+    }
+    if (!hci_transport_usb) {
+        hci_transport_usb = (hci_transport_t*)malloc( sizeof(hci_transport_t));
+        hci_transport_usb->open                          = usb_open;
+        hci_transport_usb->close                         = usb_close;
+        hci_transport_usb->send_packet                   = usb_send_packet;
+        hci_transport_usb->register_packet_handler       = usb_register_packet_handler;
+        hci_transport_usb->get_transport_name            = usb_get_transport_name;
+        hci_transport_usb->set_baudrate                  = NULL;
+        hci_transport_usb->can_send_packet_now           = NULL;
+    }
+    return hci_transport_usb;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,1138 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  l2cap.c
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#include "l2cap.h"
+#include "hci.h"
+#include "hci_dump.h"
+#include "debug.h"
+#include "btstack_memory.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <stdio.h>
+
+// nr of buffered acl packets in outgoing queue to get max performance 
+#define NR_BUFFERED_ACL_PACKETS 3
+
+// used to cache l2cap rejects, echo, and informational requests
+#define NR_PENDING_SIGNALING_RESPONSES 3
+
+// offsets for L2CAP SIGNALING COMMANDS
+#define L2CAP_SIGNALING_COMMAND_CODE_OFFSET   0
+#define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET  1
+#define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
+#define L2CAP_SIGNALING_COMMAND_DATA_OFFSET   4
+
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+// used to cache l2cap rejects, echo, and informational requests
+static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
+static int signaling_responses_pending;
+
+static linked_list_t l2cap_channels = NULL;
+static linked_list_t l2cap_services = NULL;
+static void (*packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler;
+static int new_credits_blocked = 0;
+
+static btstack_packet_handler_t attribute_protocol_packet_handler = NULL;
+static btstack_packet_handler_t security_protocol_packet_handler = NULL;
+
+// prototypes
+static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
+static l2cap_service_t * l2cap_get_service(uint16_t psm);
+static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
+static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
+static void l2cap_emit_connection_request(l2cap_channel_t *channel);
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
+
+
+void l2cap_init(){
+    new_credits_blocked = 0;
+    signaling_responses_pending = 0;
+    
+    l2cap_channels = NULL;
+    l2cap_services = NULL;
+
+    packet_handler = null_packet_handler;
+    
+    // 
+    // register callback with HCI
+    //
+    hci_register_packet_handler(&l2cap_packet_handler);
+    hci_connectable_control(0); // no services yet
+}
+
+
+/** Register L2CAP packet handlers */
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+}
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
+    packet_handler = handler;
+}
+
+//  notify client/protocol handler
+void l2cap_dispatch(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
+    if (channel->packet_handler) {
+        (* (channel->packet_handler))(type, channel->local_cid, data, size);
+    } else {
+        (*packet_handler)(channel->connection, type, channel->local_cid, data, size);
+    }
+}
+
+void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
+    uint8_t event[21];
+    event[0] = L2CAP_EVENT_CHANNEL_OPENED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_flip_addr(&event[3], channel->address);
+    bt_store_16(event,  9, channel->handle);
+    bt_store_16(event, 11, channel->psm);
+    bt_store_16(event, 13, channel->local_cid);
+    bt_store_16(event, 15, channel->remote_cid);
+    bt_store_16(event, 17, channel->local_mtu);
+    bt_store_16(event, 19, channel->remote_mtu); 
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_CHANNEL_CLOSED;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_connection_request(l2cap_channel_t *channel) {
+    uint8_t event[16];
+    event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
+    event[1] = sizeof(event) - 2;
+    bt_flip_addr(&event[2], channel->address);
+    bt_store_16(event,  8, channel->handle);
+    bt_store_16(event, 10, channel->psm);
+    bt_store_16(event, 12, channel->local_cid);
+    bt_store_16(event, 14, channel->remote_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, psm);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*packet_handler)(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
+}
+
+void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) {
+    // track credits
+    channel->packets_granted += credits;
+    // log_info("l2cap_emit_credits for cid %u, credits given: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits);
+    
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_CREDITS;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    event[4] = credits;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_block_new_credits(uint8_t blocked){
+    new_credits_blocked = blocked;
+}
+
+void l2cap_hand_out_credits(void){
+
+    if (new_credits_blocked) return;    // we're told not to. used by daemon
+    
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        if (!hci_number_free_acl_slots()) return;
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->state != L2CAP_STATE_OPEN) continue;
+        if (hci_number_outgoing_packets(channel->handle) < NR_BUFFERED_ACL_PACKETS && channel->packets_granted == 0) {
+            l2cap_emit_credits(channel, 1);
+        }
+    }
+}
+
+l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( channel->local_cid == local_cid) {
+            return channel;
+        }
+    }
+    return NULL;
+}
+
+int  l2cap_can_send_packet_now(uint16_t local_cid){
+    l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) return 0;
+    if (!channel->packets_granted) return 0;
+    return hci_can_send_packet_now(HCI_ACL_DATA_PACKET);
+}
+
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        return channel->remote_mtu;
+    } 
+    return 0;
+}
+
+int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_signaling_packet, cannot send\n");
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    // log_info("l2cap_send_signaling_packet type %u\n", cmd);
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    va_list argptr;
+    va_start(argptr, identifier);
+    uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr);
+    va_end(argptr);
+    // log_info("l2cap_send_signaling_packet con %u!\n", handle);
+    return hci_send_acl_packet(acl_buffer, len);
+}
+
+uint8_t *l2cap_get_outgoing_buffer(void){
+    return hci_get_outgoing_acl_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
+}
+
+int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_send_internal no channel for cid %u\n", local_cid);
+        return -1;   // TODO: define error
+    }
+
+    if (channel->packets_granted == 0){
+        log_error("l2cap_send_internal cid %u, no credits!\n", local_cid);
+        return -1;  // TODO: define error
+    }
+    
+    --channel->packets_granted;
+
+    log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n",
+                  local_cid, channel->handle, channel->packets_granted);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, channel->remote_cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+    
+    return err;
+}
+
+int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_prepared_to_handle cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    log_debug("l2cap_send_prepared_to_handle cid %u, handle %u\n", cid, handle);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+
+    return err;
+}
+
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    memcpy(&acl_buffer[8], data, len);
+
+    return l2cap_send_prepared(local_cid, len);
+}
+
+int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    memcpy(&acl_buffer[8], data, len);
+    
+    return l2cap_send_prepared_connectionless(handle, cid, len);
+}
+
+static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
+}
+
+static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
+}
+
+
+
+// MARK: L2CAP_RUN
+// process outstanding signaling tasks
+void l2cap_run(void){
+    
+    // check pending signaling responses
+    while (signaling_responses_pending){
+        
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        hci_con_handle_t handle = signaling_responses[0].handle;
+        uint8_t sig_id = signaling_responses[0].sig_id;
+        uint16_t infoType = signaling_responses[0].data;    // INFORMATION_REQUEST
+        uint16_t result   = signaling_responses[0].data;    // CONNECTION_REQUEST
+        
+        switch (signaling_responses[0].code){
+            case CONNECTION_REQUEST:
+                l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0);
+                break;
+            case ECHO_REQUEST:
+                l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
+                break;
+            case INFORMATION_REQUEST:
+                if (infoType == 2) {
+                    uint32_t features = 0;
+                    // extended features request supported, however no features present
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features);
+                } else {
+                    // all other types are not supported
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
+                }
+                break;
+            default:
+                // should not happen
+                break;
+        }
+        
+        // remove first item
+        signaling_responses_pending--;
+        int i;
+        for (i=0; i < signaling_responses_pending; i++){
+            memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
+        }
+    }
+    
+    uint8_t  config_options[4];
+    linked_item_t *it;
+    linked_item_t *next;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = next){
+        next = it->next;    // cache next item as current item might get freed
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        
+        // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var);
+        
+        
+        switch (channel->state){
+
+            case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
+                // send connection request - set state first
+                channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
+                // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+                hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0);
+                // discard channel - l2cap_finialize_channel_close without sending l2cap close event
+                linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list
+                btstack_memory_l2cap_channel_free(channel); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
+                channel->state = L2CAP_STATE_CONFIG;
+                channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
+                // success, start l2cap handshake
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
+                l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);                   
+                break;
+            
+            case L2CAP_STATE_CONFIG:
+                if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
+                }
+                else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
+                    channel->local_sig_id = l2cap_next_sig_id();
+                    config_options[0] = 1; // MTU
+                    config_options[1] = 2; // len param
+                    bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options);
+                }
+                if (l2cap_channel_ready_for_open(channel)){
+                    channel->state = L2CAP_STATE_OPEN;
+                    l2cap_emit_channel_opened(channel, 0);  // success
+                    l2cap_emit_credits(channel, 1);
+                }
+                break;
+
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);   
+                l2cap_finialize_channel_close(channel);  // -- remove from list
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_DISCONNECT;
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);   
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+uint16_t l2cap_max_mtu(void){
+    return hci_max_acl_data_packet_length() - L2CAP_HEADER_SIZE;
+}
+
+// open outgoing L2CAP channel
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler,
+                                   bd_addr_t address, uint16_t psm, uint16_t mtu){
+    
+    // alloc structure
+    l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!chan) {
+        // emit error event
+        l2cap_channel_t dummy_channel;
+        BD_ADDR_COPY(dummy_channel.address, address);
+        dummy_channel.psm = psm;
+        l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED);
+        return;
+    }
+    // limit local mtu to max acl packet length
+    if (mtu > l2cap_max_mtu()) {
+        mtu = l2cap_max_mtu();
+    }
+        
+    // fill in 
+    BD_ADDR_COPY(chan->address, address);
+    chan->psm = psm;
+    chan->handle = 0;
+    chan->connection = connection;
+    chan->packet_handler = packet_handler;
+    chan->remote_mtu = L2CAP_MINIMAL_MTU;
+    chan->local_mtu = mtu;
+    chan->packets_granted = 0;
+    
+    // set initial state
+    chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
+    chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    chan->remote_sig_id = L2CAP_SIG_ID_INVALID;
+    chan->local_sig_id = L2CAP_SIG_ID_INVALID;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) chan);
+    
+    l2cap_run();
+}
+
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){
+    // find channel for local_cid
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+    }
+    // process
+    l2cap_run();
+}
+
+static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
+    linked_item_t *it = (linked_item_t *) &l2cap_channels;
+    while (it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // failure, forward error code
+                l2cap_emit_channel_opened(channel, status);
+                // discard channel
+                it->next = it->next->next;
+                btstack_memory_l2cap_channel_free(channel);
+            }
+        } else {
+            it = it->next;
+        }
+    }
+}
+
+static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // success, start l2cap handshake
+                channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
+                channel->handle = handle;
+                channel->local_cid = l2cap_next_local_cid();
+            }
+        }
+    }
+    // process
+    l2cap_run();
+}
+
+void l2cap_event_handler( uint8_t *packet, uint16_t size ){
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    l2cap_channel_t * channel;
+    linked_item_t *it;
+    int hci_con_used;
+    
+    switch(packet[0]){
+            
+        // handle connection complete events
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            bt_flip_addr(address, &packet[5]);
+            if (packet[2] == 0){
+                handle = READ_BT_16(packet, 3);
+                l2cap_handle_connection_success_for_addr(address, handle);
+            } else {
+                l2cap_handle_connection_failed_for_addr(address, packet[2]);
+            }
+            break;
+            
+        // handle successful create connection cancel command
+        case HCI_EVENT_COMMAND_COMPLETE:
+            if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) {
+                if (packet[5] == 0){
+                    bt_flip_addr(address, &packet[6]);
+                    // CONNECTION TERMINATED BY LOCAL HOST (0X16)
+                    l2cap_handle_connection_failed_for_addr(address, 0x16);
+                }
+            }
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        // handle disconnection complete events
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            // send l2cap disconnect events for all channels on this handle
+            handle = READ_BT_16(packet, 3);
+            it = (linked_item_t *) &l2cap_channels;
+            while (it->next){
+                l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+                if ( channel->handle == handle ){
+                    // update prev item before free'ing next element - don't call l2cap_finalize_channel_close
+                    it->next = it->next->next;
+                    l2cap_emit_channel_closed(channel);
+                    btstack_memory_l2cap_channel_free(channel);
+                } else {
+                    it = it->next;
+                }
+            }
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            l2cap_run();    // try sending signaling packets first
+            l2cap_hand_out_credits();
+            break;
+            
+        // HCI Connection Timeouts
+        case L2CAP_EVENT_TIMEOUT_CHECK:
+            handle = READ_BT_16(packet, 2);
+            if (hci_authentication_active_for_handle(handle)) break;
+            hci_con_used = 0;
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->handle == handle) {
+                    hci_con_used = 1;
+                }
+            }
+            if (hci_con_used) break;
+            if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+            hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection             
+            break;
+
+        case DAEMON_EVENT_HCI_PACKET_SENT:
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->packet_handler) {
+                    (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size);
+                } 
+            }
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            break;
+            
+        default:
+            break;
+    }
+    
+    // pass on
+    (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size);
+}
+
+static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
+    channel->remote_sig_id = identifier;
+    channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
+    l2cap_run();
+}
+
+static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){
+    // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused."
+    if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
+        signaling_responses[signaling_responses_pending].handle = handle;
+        signaling_responses[signaling_responses_pending].code = code;
+        signaling_responses[signaling_responses_pending].sig_id = sig_id;
+        signaling_responses[signaling_responses_pending].data = data;
+        signaling_responses_pending++;
+        l2cap_run();
+    }
+}
+
+static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
+    
+    // log_info("l2cap_handle_connection_request for handle %u, psm %u cid %u\n", handle, psm, source_cid);
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) {
+        // 0x0002 PSM not supported
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002);
+        return;
+    }
+    
+    hci_connection_t * hci_connection = connection_for_handle( handle );
+    if (!hci_connection) {
+        // 
+        log_error("no hci_connection for handle %u\n", handle);
+        return;
+    }
+    // alloc structure
+    // log_info("l2cap_handle_connection_request register channel\n");
+    l2cap_channel_t * channel = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!channel){
+        // 0x0004 No resources available
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004);
+        return;
+    }
+    
+    // fill in 
+    BD_ADDR_COPY(channel->address, hci_connection->address);
+    channel->psm = psm;
+    channel->handle = handle;
+    channel->connection = service->connection;
+    channel->packet_handler = service->packet_handler;
+    channel->local_cid  = l2cap_next_local_cid();
+    channel->remote_cid = source_cid;
+    channel->local_mtu  = service->mtu;
+    channel->remote_mtu = L2CAP_DEFAULT_MTU;
+    channel->packets_granted = 0;
+    channel->remote_sig_id = sig_id; 
+
+    // limit local mtu to max acl packet length
+    if (channel->local_mtu > l2cap_max_mtu()) {
+        channel->local_mtu = l2cap_max_mtu();
+    }
+    
+    // set initial state
+    channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
+    channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) channel);
+    
+    // emit incoming connection request
+    l2cap_emit_connection_request(channel);
+}
+
+void l2cap_accept_connection_internal(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+
+    channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
+
+    // process
+    l2cap_run();
+}
+
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
+    if (!channel) {
+        log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+    channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
+    channel->reason = reason;
+    l2cap_run();
+}
+
+void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
+
+    channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+
+    // accept the other's configuration options
+    uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+    uint16_t pos     = 8;
+    while (pos < end_pos){
+        uint8_t type   = command[pos++];
+        uint8_t length = command[pos++];
+        // MTU { type(8): 1, len(8):2, MTU(16) }
+        if ((type & 0x7f) == 1 && length == 2){
+            channel->remote_mtu = READ_BT_16(command, pos);
+            // log_info("l2cap cid %u, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
+        }
+        pos += length;
+    }
+}
+
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
+    // log_info("l2cap_channel_ready_for_open 0x%02x\n", channel->state_var);
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
+    return 1;
+}
+
+
+void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
+
+    uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    uint16_t result = 0;
+    
+    log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state);
+    
+    // handle DISCONNECT REQUESTS seperately
+    if (code == DISCONNECTION_REQUEST){
+        switch (channel->state){
+            case L2CAP_STATE_CONFIG:
+            case L2CAP_STATE_OPEN:
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+            case L2CAP_STATE_WAIT_DISCONNECT:
+                l2cap_handle_disconnect_request(channel, identifier);
+                break;
+
+            default:
+                // ignore in other states
+                break;
+        }
+        return;
+    }
+    
+    // @STATEMACHINE(l2cap)
+    switch (channel->state) {
+            
+        case L2CAP_STATE_WAIT_CONNECT_RSP:
+            switch (code){
+                case CONNECTION_RESPONSE:
+                    result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
+                    switch (result) {
+                        case 0:
+                            // successful connection
+                            channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+                            channel->state = L2CAP_STATE_CONFIG;
+                            channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                            break;
+                        case 1:
+                            // connection pending. get some coffee
+                            break;
+                        default:
+                            // channel closed
+                            channel->state = L2CAP_STATE_CLOSED;
+
+                            // map l2cap connection response result to BTstack status enumeration
+                            l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
+                            
+                            // drop link key if security block
+                            if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
+                                hci_drop_link_key_for_bd_addr(&channel->address);
+                            }
+                            
+                            // discard channel
+                            linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+                            btstack_memory_l2cap_channel_free(channel);
+                            break;
+                    }
+                    break;
+                    
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+
+        case L2CAP_STATE_CONFIG:
+            switch (code) {
+                case CONFIGURE_REQUEST:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    l2cap_signaling_handle_configure_request(channel, command);
+                    break;
+                case CONFIGURE_RESPONSE:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
+                    break;
+                default:
+                    break;
+            }
+            if (l2cap_channel_ready_for_open(channel)){
+                // for open:
+                channel->state = L2CAP_STATE_OPEN;
+                l2cap_emit_channel_opened(channel, 0);
+                l2cap_emit_credits(channel, 1);
+            }
+            break;
+            
+        case L2CAP_STATE_WAIT_DISCONNECT:
+            switch (code) {
+                case DISCONNECTION_RESPONSE:
+                    l2cap_finialize_channel_close(channel);
+                    break;
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+            
+        case L2CAP_STATE_CLOSED:
+            // @TODO handle incoming requests
+            break;
+            
+        case L2CAP_STATE_OPEN:
+            //@TODO: implement other signaling packets, e.g. re-configure
+            break;
+        default:
+            break;
+    }
+    // log_info("new state %u\n", channel->state);
+}
+
+
+void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
+    
+    // get code, signalind identifier and command len
+    uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    
+    // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST 
+    if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
+        return;
+    }
+
+    // general commands without an assigned channel
+    switch(code) {
+            
+        case CONNECTION_REQUEST: {
+            uint16_t psm =        READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            uint16_t source_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
+            l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
+            return;
+        }
+            
+        case ECHO_REQUEST:
+            l2cap_register_signaling_response(handle, code, sig_id, 0);
+            return;
+            
+        case INFORMATION_REQUEST: {
+            uint16_t infoType = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            l2cap_register_signaling_response(handle, code, sig_id, infoType);
+            return;
+        }
+            
+        default:
+            break;
+    }
+    
+    
+    // Get potential destination CID
+    uint16_t dest_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+    
+    // Find channel for this sig_id and connection handle
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->handle == handle) {
+            if (code & 1) {
+                // match odd commands (responses) by previous signaling identifier 
+                if (channel->local_sig_id == sig_id) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            } else {
+                // match even commands (requests) by local channel id
+                if (channel->local_cid == dest_cid) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
+        
+    // Get Channel ID
+    uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 
+    hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
+    
+    switch (channel_id) {
+            
+        case L2CAP_CID_SIGNALING: {
+            
+            uint16_t command_offset = 8;
+            while (command_offset < size) {                
+                
+                // handle signaling commands
+                l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
+                
+                // increment command_offset
+                command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+            }
+            break;
+        }
+            
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+            
+        default: {
+            // Find channel for this channel_id and connection handle
+            l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id);
+            if (channel) {
+                l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+        }
+    }
+    
+    l2cap_run();
+}
+
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            l2cap_event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            l2cap_acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
+void l2cap_finialize_channel_close(l2cap_channel_t *channel){
+    channel->state = L2CAP_STATE_CLOSED;
+    l2cap_emit_channel_closed(channel);
+    // discard channel
+    linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+    btstack_memory_l2cap_channel_free(channel);
+}
+
+l2cap_service_t * l2cap_get_service(uint16_t psm){
+    linked_item_t *it;
+    
+    // close open channels
+    for (it = (linked_item_t *) l2cap_services; it ; it = it->next){
+        l2cap_service_t * service = ((l2cap_service_t *) it);
+        if ( service->psm == psm){
+            return service;
+        };
+    }
+    return NULL;
+}
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu){
+    // check for alread registered psm 
+    // TODO: emit error event
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (service) {
+        log_error("l2cap_register_service_internal: PSM %u already registered\n", psm);
+        l2cap_emit_service_registered(connection, L2CAP_SERVICE_ALREADY_REGISTERED, psm);
+        return;
+    }
+    
+    // alloc structure
+    // TODO: emit error event
+    service = (l2cap_service_t *) btstack_memory_l2cap_service_get();
+    if (!service) {
+        log_error("l2cap_register_service_internal: no memory for l2cap_service_t\n");
+        l2cap_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, psm);
+        return;
+    }
+    
+    // fill in 
+    service->psm = psm;
+    service->mtu = mtu;
+    service->connection = connection;
+    service->packet_handler = packet_handler;
+
+    // add to services list
+    linked_list_add(&l2cap_services, (linked_item_t *) service);
+    
+    // enable page scan
+    hci_connectable_control(1);
+
+    // done
+    l2cap_emit_service_registered(connection, 0, psm);
+}
+
+void l2cap_unregister_service_internal(void *connection, uint16_t psm){
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) return;
+    linked_list_remove(&l2cap_services, (linked_item_t *) service);
+    btstack_memory_l2cap_service_free(service);
+    
+    // disable page scan when no services registered
+    if (!linked_list_empty(&l2cap_services)) return;
+    hci_connectable_control(0);
+}
+
+//
+void l2cap_close_connection(void *connection){
+    linked_item_t *it;
+    
+    // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks
+    l2cap_channel_t * channel;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        channel = (l2cap_channel_t *) it;
+        if (channel->connection == connection) {
+            channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+        }
+    }   
+    
+    // unregister services
+    it = (linked_item_t *) &l2cap_services;
+    while (it->next) {
+        l2cap_service_t * service = (l2cap_service_t *) it->next;
+        if (service->connection == connection){
+            it->next = it->next->next;
+            btstack_memory_l2cap_service_free(service);
+        } else {
+            it = it->next;
+        }
+    }
+    
+    // process
+    l2cap_run();
+}
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id) {
+    switch(channel_id){
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            attribute_protocol_packet_handler = packet_handler;
+            break;
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            security_protocol_packet_handler = packet_handler;
+            break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,201 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  l2cap.h
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#pragma once
+
+#include "hci.h"
+#include "l2cap_signaling.h"
+#include <btstack/utils.h>
+#include <btstack/btstack.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+#define L2CAP_SIG_ID_INVALID 0
+
+#define L2CAP_HEADER_SIZE 4
+
+// size of HCI ACL + L2CAP Header for regular data packets (8)
+#define COMPLETE_L2CAP_HEADER (HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE)
+    
+// minimum signaling MTU
+#define L2CAP_MINIMAL_MTU 48
+#define L2CAP_DEFAULT_MTU 672
+    
+// check L2CAP MTU
+#if (L2CAP_MINIMAL_MTU + L2CAP_HEADER_SIZE) > HCI_ACL_PAYLOAD_SIZE
+#error "HCI_ACL_PAYLOAD_SIZE too small for minimal L2CAP MTU of 48 bytes"
+#endif    
+    
+// L2CAP Fixed Channel IDs    
+#define L2CAP_CID_SIGNALING                 0x0001
+#define L2CAP_CID_CONNECTIONLESS_CHANNEL    0x0002
+#define L2CAP_CID_ATTRIBUTE_PROTOCOL        0x0004
+#define L2CAP_CID_SIGNALING_LE              0x0005
+#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
+    
+void l2cap_init(void);
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason);
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid);
+uint16_t l2cap_max_mtu(void);
+
+void l2cap_block_new_credits(uint8_t blocked);
+int  l2cap_can_send_packet_now(uint16_t local_cid);    // non-blocking UART write
+
+// get outgoing buffer and prepare data
+uint8_t *l2cap_get_outgoing_buffer(void);
+
+int  l2cap_send_prepared(uint16_t local_cid, uint16_t len);
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len);
+
+int  l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len);
+int  l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len);
+    
+void l2cap_close_connection(void *connection);
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu);
+void l2cap_unregister_service_internal(void *connection, uint16_t psm);
+
+void l2cap_accept_connection_internal(uint16_t local_cid);
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason);
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id);
+
+
+// private structs
+typedef enum {
+    L2CAP_STATE_CLOSED = 1,           // no baseband
+    L2CAP_STATE_WILL_SEND_CREATE_CONNECTION,
+    L2CAP_STATE_WAIT_CONNECTION_COMPLETE,
+    L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT,
+    L2CAP_STATE_WAIT_CONNECT_RSP, // from peer
+    L2CAP_STATE_CONFIG,
+    L2CAP_STATE_OPEN,
+    L2CAP_STATE_WAIT_DISCONNECT,  // from application
+    L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT,   
+    L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST,
+    L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE,
+} L2CAP_STATE;
+
+typedef enum {
+    L2CAP_CHANNEL_STATE_VAR_NONE          = 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
+} L2CAP_CHANNEL_STATE_VAR;
+
+// info regarding an actual coneection
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    L2CAP_STATE state;
+    L2CAP_CHANNEL_STATE_VAR state_var;
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    
+    uint8_t   remote_sig_id;    // used by other side, needed for delayed response
+    uint8_t   local_sig_id;     // own signaling identifier
+    
+    uint16_t  local_cid;
+    uint16_t  remote_cid;
+    
+    uint16_t  local_mtu;
+    uint16_t  remote_mtu;
+    
+    uint16_t  psm;
+    
+    uint8_t   packets_granted;    // number of L2CAP/ACL packets client is allowed to send
+    
+    uint8_t   reason; // used in decline internal
+    
+    // client connection
+    void * connection;
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_channel_t;
+
+// info regarding potential connections
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // service id
+    uint16_t  psm;
+    
+    // incoming MTU
+    uint16_t mtu;
+    
+    // client connection
+    void *connection;    
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_service_t;
+
+
+typedef struct l2cap_signaling_response {
+    hci_con_handle_t handle;
+    uint8_t  sig_id;
+    uint8_t  code;
+    uint16_t data; // infoType for INFORMATION REQUEST, result for CONNECTION request
+} l2cap_signaling_response_t;
+    
+    
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap_signaling.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,128 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include "l2cap_signaling.h"
+
+#include <string.h>
+
+static char *l2cap_signaling_commands_format[] = {
+"D",    // 0x01 command reject: reason {cmd not understood (0), sig MTU exceeded (2:max sig MTU), invalid CID (4:req CID)}, data len, data
+"22",   // 0x02 connection request: PSM, Source CID
+"2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
+"22D",  // 0x04 config request: Dest CID, Flags, Configuration options
+"222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
+"22",   // 0x06 disconection request: Dest CID, Source CID
+"22",   // 0x07 disconection response: Dest CID, Source CID
+"D",    // 0x08 echo request: Data
+"D",    // 0x09 echo response: Data
+"2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
+"22D",  // 0x0b information response: InfoType, Result, Data
+};
+
+uint8_t   sig_seq_nr  = 0xff;
+uint16_t  source_cid  = 0x40;
+
+uint8_t l2cap_next_sig_id(void){
+    if (sig_seq_nr == 0xff) {
+        sig_seq_nr = 1;
+    } else {
+        sig_seq_nr++;
+    }
+    return sig_seq_nr;
+}
+
+uint16_t l2cap_next_local_cid(void){
+    return source_cid++;
+}
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 6 - L2CAP channel = 1
+    bt_store_16(acl_buffer, 6, 1);
+    // 8 - Code
+    acl_buffer[8] = cmd;
+    // 9 - id (!= 0 sequentially)
+    acl_buffer[9] = identifier;
+    
+    // 12 - L2CAP signaling parameters
+    uint16_t pos = 12;
+    const char *format = l2cap_signaling_commands_format[cmd-1];
+    uint16_t word;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+                word = va_arg(argptr, int);
+                // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                acl_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    acl_buffer[pos++] = word >> 8;
+                }
+                break;
+            case 'D': // variable data. passed: len, ptr
+                word = va_arg(argptr, int);
+                ptr  = va_arg(argptr, uint8_t *);
+                memcpy(&acl_buffer[pos], ptr, word);
+                pos += word;
+                break;
+            default:
+                break;
+        }
+        format++;
+    };
+    va_end(argptr);
+    
+    // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
+    // - the l2cap payload length is counted after the following channel id (only payload) 
+    
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  pos - 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  pos - 6 - 2);
+    // 10 - L2CAP signaling parameter length
+    bt_store_16(acl_buffer, 10, pos - 12);
+    
+    return pos;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap_signaling.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <btstack/utils.h>
+#include <btstack/hci_cmds.h>
+
+typedef enum {
+    COMMAND_REJECT = 1,
+    CONNECTION_REQUEST,
+    CONNECTION_RESPONSE,
+    CONFIGURE_REQUEST,
+    CONFIGURE_RESPONSE,
+    DISCONNECTION_REQUEST,
+    DISCONNECTION_RESPONSE,
+    ECHO_REQUEST,
+    ECHO_RESPONSE,
+    INFORMATION_REQUEST,
+    INFORMATION_RESPONSE
+} L2CAP_SIGNALING_COMMANDS;
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr);
+uint8_t  l2cap_next_sig_id(void);
+uint16_t l2cap_next_local_cid(void);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/linked_list.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  linked_list.c
+ *
+ *  Created by Matthias Ringwald on 7/13/09.
+ */
+
+#include <btstack/linked_list.h>
+#include <stdlib.h>
+/**
+ * tests if list is empty
+ */
+int  linked_list_empty(linked_list_t * list){
+    return *list == (void *) 0;
+}
+
+/**
+ * linked_list_get_last_item
+ */
+linked_item_t * linked_list_get_last_item(linked_list_t * list){        // <-- find the last item in the list
+    linked_item_t *lastItem = NULL;
+    linked_item_t *it;
+    for (it = *list; it ; it = it->next){
+        if (it) {
+            lastItem = it;
+        }
+    }
+    return lastItem;
+}
+
+
+/**
+ * linked_list_add
+ */
+void linked_list_add(linked_list_t * list, linked_item_t *item){        // <-- add item to list
+    // check if already in list
+    linked_item_t *it;
+    for (it = *list; it ; it = it->next){
+        if (it == item) {
+            return;
+        }
+    }
+    // add first
+    item->next = *list;
+    *list = item;
+}
+
+void linked_list_add_tail(linked_list_t * list, linked_item_t *item){   // <-- add item to list as last element
+    // check if already in list
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it->next ; it = it->next){
+        if (it->next == item) {
+            return;
+        }
+    }
+    item->next = (linked_item_t*) 0;
+    it->next = item;
+}
+
+/**
+ * Remove data_source from run loop
+ *
+ * @note: assumes that data_source_t.next is first element in data_source
+ */
+int  linked_list_remove(linked_list_t * list, linked_item_t *item){    // <-- remove item from list
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it ; it = it->next){
+        if (it->next == item){
+            it->next =  item->next;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+void linked_item_set_user(linked_item_t *item, void *user_data){
+    item->next = (linked_item_t *) 0;
+    item->user_data = user_data;
+}
+
+void * linked_item_get_user(linked_item_t *item) {
+    return item->user_data;
+}
+
+#if 0
+#include <stdio.h>
+void test_linked_list(){
+    linked_list_t testList = 0;
+    linked_item_t itemA;
+    linked_item_t itemB;
+    linked_item_t itemC;
+    linked_item_set_user(&itemA, (void *) 0);
+    linked_item_set_user(&itemB, (void *) 0);
+    linked_list_add(&testList, &itemA);
+    linked_list_add(&testList, &itemB);
+    linked_list_add_tail(&testList, &itemC);
+    // linked_list_remove(&testList, &itemB);
+    linked_item_t *it;
+    for (it = (linked_item_t *) &testList; it ; it = it->next){
+        if (it->next == &itemA) printf("Item A\n");
+        if (it->next == &itemB) printf("Item B\n");
+        if (it->next == &itemC) printf("Item C\n");
+        /* if (it->next == &itemB){
+            it->next =  it->next;
+            printf(" remove\n");
+        } else {
+            printf(" keep\n");
+        
+         */
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/memory_pool.c	Mon Nov 30 09:32:15 2015 +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	Mon Nov 30 09:32:15 2015 +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 | DYNAMIC
+    0x0d, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x28, 0x04, 0x0b, 0x00, 0xf1, 0xff, 
+    // 0x000b VALUE-FFF1-READ | DYNAMIC-
+    0x08, 0x00, 0x04, 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 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/remote_device_db.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ */
+
+/**
+ * interface to provide link key and remote name storage
+ */
+
+#pragma once
+
+#include <btstack/utils.h>
+
+typedef struct {
+
+    // management
+    void (*open)(void);
+    void (*close)(void);
+    
+    // link key
+    int  (*get_link_key)(bd_addr_t *bd_addr, link_key_t *link_key);
+    void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
+    void (*delete_link_key)(bd_addr_t *bd_addr);
+    
+    // remote name
+    int  (*get_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*delete_name)(bd_addr_t *bd_addr);
+
+    // persistent rfcomm channel
+    uint8_t (*persistent_rfcomm_channel)(char *servicename);
+
+} remote_device_db_t;
+
+extern remote_device_db_t remote_device_db_iphone;
+extern const remote_device_db_t remote_device_db_memory;
+
+// MARK: non-persisten implementation
+#include <btstack/linked_list.h>
+#define MAX_NAME_LEN 32
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    bd_addr_t bd_addr;
+} db_mem_device_t;
+
+typedef struct {
+    db_mem_device_t device;
+    link_key_t link_key;
+} db_mem_device_link_key_t;
+
+typedef struct {
+    db_mem_device_t device;
+    char device_name[MAX_NAME_LEN];
+} db_mem_device_name_t;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    char service_name[MAX_NAME_LEN];
+    uint8_t channel;
+} db_mem_service_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/remote_device_db_memory.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,198 @@
+/*
+ * 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
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "remote_device_db.h"
+#include "btstack_memory.h"
+#include "debug.h"
+
+#include <btstack/utils.h>
+#include <btstack/linked_list.h>
+
+// This lists should be only accessed by tests.
+linked_list_t db_mem_link_keys = NULL;
+linked_list_t db_mem_names = NULL;
+static linked_list_t db_mem_services = NULL;
+
+// Device info
+static void db_open(void){
+}
+
+static void db_close(void){ 
+}
+
+static db_mem_device_t * get_item(linked_list_t list, bd_addr_t *bd_addr) {
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it ; it = it->next){
+        db_mem_device_t * item = (db_mem_device_t *) it;
+        if (BD_ADDR_CMP(item->bd_addr, *bd_addr) == 0) {
+            return item;
+        }
+    }
+    return NULL;
+}
+
+static int get_name(bd_addr_t *bd_addr, device_name_t *device_name) {
+    db_mem_device_name_t * item = (db_mem_device_name_t *) get_item(db_mem_names, bd_addr);
+    
+    if (!item) return 0;
+    
+    strncpy((char*)device_name, item->device_name, MAX_NAME_LEN);
+    
+	linked_list_remove(&db_mem_names, (linked_item_t *) item);
+    linked_list_add(&db_mem_names, (linked_item_t *) item);
+	
+	return 1;
+}
+
+static int get_link_key(bd_addr_t *bd_addr, link_key_t *link_key) {
+    db_mem_device_link_key_t * item = (db_mem_device_link_key_t *) get_item(db_mem_link_keys, bd_addr);
+    
+    if (!item) return 0;
+    
+    memcpy(link_key, item->link_key, LINK_KEY_LEN);
+    
+	linked_list_remove(&db_mem_link_keys, (linked_item_t *) item);
+    linked_list_add(&db_mem_link_keys, (linked_item_t *) item);
+
+	return 1;
+}
+
+static void delete_link_key(bd_addr_t *bd_addr){
+    db_mem_device_t * item = get_item(db_mem_link_keys, bd_addr);
+    
+    if (!item) return;
+    
+    linked_list_remove(&db_mem_link_keys, (linked_item_t *) item);
+    btstack_memory_db_mem_device_link_key_free(item);
+}
+
+
+static void put_link_key(bd_addr_t *bd_addr, link_key_t *link_key){
+    db_mem_device_link_key_t * existingRecord = (db_mem_device_link_key_t *) get_item(db_mem_link_keys, bd_addr);
+    
+    if (existingRecord){
+        memcpy(existingRecord->link_key, link_key, LINK_KEY_LEN);
+        return;
+    }
+    
+    // Record not found, create new one for this device
+    db_mem_device_link_key_t * newItem = (db_mem_device_link_key_t*) btstack_memory_db_mem_device_link_key_get();
+    if (!newItem){
+        newItem = (db_mem_device_link_key_t*)linked_list_get_last_item(&db_mem_link_keys);
+    }
+    
+    if (!newItem) return;
+    
+    memcpy(newItem->device.bd_addr, bd_addr, sizeof(bd_addr_t));
+    memcpy(newItem->link_key, link_key, LINK_KEY_LEN);
+    linked_list_add(&db_mem_link_keys, (linked_item_t *) newItem);
+}
+
+static void delete_name(bd_addr_t *bd_addr){
+    db_mem_device_t * item = get_item(db_mem_names, bd_addr);
+    
+    if (!item) return;
+    
+    linked_list_remove(&db_mem_names, (linked_item_t *) item);
+    btstack_memory_db_mem_device_name_free(item);    
+}
+
+static void put_name(bd_addr_t *bd_addr, device_name_t *device_name){
+    db_mem_device_name_t * existingRecord = (db_mem_device_name_t *) get_item(db_mem_names, bd_addr);
+    
+    if (existingRecord){
+        strncpy(existingRecord->device_name, (const char*) device_name, MAX_NAME_LEN);
+        return;
+    }
+    
+    // Record not found, create a new one for this device
+    db_mem_device_name_t * newItem = (db_mem_device_name_t *) btstack_memory_db_mem_device_name_get();
+    if (!newItem) {
+        newItem = (db_mem_device_name_t*)linked_list_get_last_item(&db_mem_names);
+    };
+
+    if (!newItem) return;
+    
+    memcpy(newItem->device.bd_addr, bd_addr, sizeof(bd_addr_t));
+    strncpy(newItem->device_name, (const char*) device_name, MAX_NAME_LEN);
+    linked_list_add(&db_mem_names, (linked_item_t *) newItem);
+}
+
+
+// MARK: PERSISTENT RFCOMM CHANNEL ALLOCATION
+
+static uint8_t persistent_rfcomm_channel(char *serviceName){
+    linked_item_t *it;
+    db_mem_service_t * item;
+    uint8_t max_channel = 1;
+
+    for (it = (linked_item_t *) db_mem_services; it ; it = it->next){
+        item = (db_mem_service_t *) it;
+        if (strncmp(item->service_name, serviceName, MAX_NAME_LEN) == 0) {
+            // Match found
+            return item->channel;
+        }
+
+        // TODO prevent overflow
+        if (item->channel >= max_channel) max_channel = item->channel + 1;
+    }
+
+    // Allocate new persistant channel
+    db_mem_service_t * newItem = (db_mem_service_t *) btstack_memory_db_mem_service_get();
+
+    if (!newItem) return 0;
+    
+    strncpy(newItem->service_name, serviceName, MAX_NAME_LEN);
+    newItem->channel = max_channel;
+    linked_list_add(&db_mem_services, (linked_item_t *) newItem);
+    return max_channel;
+}
+
+
+const remote_device_db_t remote_device_db_memory = {
+    db_open,
+    db_close,
+    get_link_key,
+    put_link_key,
+    delete_link_key,
+    get_name,
+    put_name,
+    delete_name,
+    persistent_rfcomm_channel
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/rfcomm.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,278 @@
+/*
+ * 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.h
+ */
+
+#include <btstack/btstack.h>
+#include <btstack/utils.h>
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+void rfcomm_init(void);
+
+// register packet handler
+void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                    uint16_t channel, uint8_t *packet, uint16_t size));
+
+// BTstack Internal RFCOMM API
+void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t channel);
+void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits);
+void rfcomm_disconnect_internal(uint16_t rfcomm_cid);
+void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size);
+void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits);
+void rfcomm_unregister_service_internal(uint8_t service_channel);
+void rfcomm_accept_connection_internal(uint16_t rfcomm_cid);
+void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);
+void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits);
+int  rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len);
+void rfcomm_close_connection(void *connection);
+
+#define UNLIMITED_INCOMING_CREDITS 0xff
+
+// private structs
+typedef enum {
+    RFCOMM_MULTIPLEXER_CLOSED = 1,
+    RFCOMM_MULTIPLEXER_W4_CONNECT,  // outgoing
+    RFCOMM_MULTIPLEXER_SEND_SABM_0,     //    "
+    RFCOMM_MULTIPLEXER_W4_UA_0,     //    "
+    RFCOMM_MULTIPLEXER_W4_SABM_0,   // incoming
+    RFCOMM_MULTIPLEXER_SEND_UA_0,
+    RFCOMM_MULTIPLEXER_OPEN,
+    RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC
+} RFCOMM_MULTIPLEXER_STATE;
+
+typedef enum {
+    MULT_EV_READY_TO_SEND = 1,
+    
+} RFCOMM_MULTIPLEXER_EVENT;
+
+typedef enum {
+    RFCOMM_CHANNEL_CLOSED = 1,
+    RFCOMM_CHANNEL_W4_MULTIPLEXER,
+    RFCOMM_CHANNEL_SEND_UIH_PN,
+    RFCOMM_CHANNEL_W4_PN_RSP,
+    RFCOMM_CHANNEL_SEND_SABM_W4_UA,
+    RFCOMM_CHANNEL_W4_UA,
+    RFCOMM_CHANNEL_INCOMING_SETUP,
+    RFCOMM_CHANNEL_DLC_SETUP,
+    RFCOMM_CHANNEL_OPEN,
+    RFCOMM_CHANNEL_SEND_UA_AFTER_DISC,
+    RFCOMM_CHANNEL_SEND_DISC,
+    RFCOMM_CHANNEL_SEND_DM,
+    
+} RFCOMM_CHANNEL_STATE;
+
+typedef 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,
+} RFCOMM_CHANNEL_STATE_VAR;
+
+typedef enum {
+    CH_EVT_RCVD_SABM = 1,
+    CH_EVT_RCVD_UA,
+    CH_EVT_RCVD_PN,
+    CH_EVT_RCVD_PN_RSP,
+    CH_EVT_RCVD_DISC,
+    CH_EVT_RCVD_DM,
+    CH_EVT_RCVD_MSC_CMD,
+    CH_EVT_RCVD_MSC_RSP,
+    CH_EVT_RCVD_RPN_CMD,
+    CH_EVT_RCVD_RPN_REQ,
+    CH_EVT_RCVD_CREDITS,
+    CH_EVT_MULTIPLEXER_READY,
+    CH_EVT_READY_TO_SEND,
+} RFCOMM_CHANNEL_EVENT;
+
+typedef struct rfcomm_channel_event {
+    RFCOMM_CHANNEL_EVENT type;
+} rfcomm_channel_event_t;
+
+typedef struct rfcomm_channel_event_pn {
+    rfcomm_channel_event_t super;
+    uint16_t max_frame_size;
+    uint8_t  priority;
+    uint8_t  credits_outgoing;
+} rfcomm_channel_event_pn_t;
+
+typedef struct rfcomm_rpn_data {
+    uint8_t baud_rate;
+    uint8_t flags;
+    uint8_t flow_control;
+    uint8_t xon;
+    uint8_t xoff;
+    uint8_t parameter_mask_0;   // first byte
+    uint8_t parameter_mask_1;   // second byte
+} rfcomm_rpn_data_t;
+
+typedef struct rfcomm_channel_event_rpn {
+    rfcomm_channel_event_t super;
+    rfcomm_rpn_data_t data;
+} rfcomm_channel_event_rpn_t;
+
+// info regarding potential connections
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // server channel
+    uint8_t server_channel;
+    
+    // incoming max frame size
+    uint16_t max_frame_size;
+
+    // use incoming flow control
+    uint8_t incoming_flow_control;
+    
+    // initial incoming credits
+    uint8_t incoming_initial_credits;
+    
+    // client connection
+    void *connection;    
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} rfcomm_service_t;
+
+// info regarding multiplexer
+// note: spec mandates single multplexer per device combination
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    timer_source_t   timer;
+    int              timer_active;
+    
+    RFCOMM_MULTIPLEXER_STATE state; 
+    
+    uint16_t  l2cap_cid;
+    uint8_t   l2cap_credits;
+    
+    bd_addr_t remote_addr;
+    hci_con_handle_t con_handle;
+    
+    uint8_t   outgoing;
+    
+    // hack to deal with authentication failure only observed by remote side
+    uint8_t   at_least_one_connection;
+    
+    uint16_t max_frame_size;
+    
+    // send DM for DLCI != 0
+    uint8_t send_dm_for_dlci;
+    
+} rfcomm_multiplexer_t;
+
+// info regarding an actual coneection
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    rfcomm_multiplexer_t *multiplexer;
+    uint16_t rfcomm_cid;
+    uint8_t  outgoing;
+    uint8_t  dlci; 
+    
+    // number of packets granted to client
+    uint8_t packets_granted;
+
+    // credits for outgoing traffic
+    uint8_t credits_outgoing;
+    
+    // number of packets remote will be granted
+    uint8_t new_credits_incoming;
+
+    // credits for incoming traffic
+    uint8_t credits_incoming;
+    
+    // use incoming flow control
+    uint8_t incoming_flow_control;
+    
+    // channel state
+    RFCOMM_CHANNEL_STATE state;
+    
+    // state variables used in RFCOMM_CHANNEL_INCOMING
+    RFCOMM_CHANNEL_STATE_VAR state_var;
+    
+    // priority set by incoming side in PN
+    uint8_t pn_priority;
+    
+    // negotiated frame size
+    uint16_t max_frame_size;
+    
+    // rpn data
+    rfcomm_rpn_data_t rpn_data;
+    
+    // server channel (see rfcomm_service_t) - NULL => outgoing channel
+    rfcomm_service_t * service;
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+    // client connection
+    void * connection;
+    
+} rfcomm_channel_t;
+
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/run_loop.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,153 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  run_loop.c
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#include <btstack/run_loop.h>
+
+#include <stdio.h>
+#include <stdlib.h>  // exit()
+
+#include "run_loop_private.h"
+
+#include "debug.h"
+#include "config.h"
+
+static run_loop_t * the_run_loop = NULL;
+
+extern const run_loop_t run_loop_embedded;
+
+#ifdef USE_POSIX_RUN_LOOP
+extern run_loop_t run_loop_posix;
+#endif
+
+#ifdef USE_COCOA_RUN_LOOP
+extern run_loop_t run_loop_cocoa;
+#endif
+
+// assert run loop initialized
+void run_loop_assert(void){
+#ifndef EMBEDDED
+    if (!the_run_loop){
+        log_error("ERROR: run_loop function called before run_loop_init!\n");
+        exit(10);
+    }
+#endif
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void run_loop_add_data_source(data_source_t *ds){
+    run_loop_assert();
+    the_run_loop->add_data_source(ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int run_loop_remove_data_source(data_source_t *ds){
+    run_loop_assert();
+    return the_run_loop->remove_data_source(ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void run_loop_add_timer(timer_source_t *ts){
+    run_loop_assert();
+    the_run_loop->add_timer(ts);
+}
+
+/**
+ * Remove timer from run loop
+ */
+int run_loop_remove_timer(timer_source_t *ts){
+    run_loop_assert();
+    return the_run_loop->remove_timer(ts);
+}
+
+void run_loop_timer_dump(){
+    run_loop_assert();
+    the_run_loop->dump_timer();
+}
+
+/**
+ * Execute run_loop
+ */
+void run_loop_execute() {
+    run_loop_assert();
+    the_run_loop->execute();
+}
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type){
+#ifndef EMBEDDED
+    if (the_run_loop){
+        log_error("ERROR: run loop initialized twice!\n");
+        exit(10);
+    }
+#endif
+    switch (type) {
+#ifdef EMBEDDED
+        case RUN_LOOP_EMBEDDED:
+            the_run_loop = (run_loop_t*) &run_loop_embedded;
+            break;
+#endif
+#ifdef USE_POSIX_RUN_LOOP
+        case RUN_LOOP_POSIX:
+            the_run_loop = &run_loop_posix;
+            break;
+#endif
+#ifdef USE_COCOA_RUN_LOOP
+        case RUN_LOOP_COCOA:
+            the_run_loop = &run_loop_cocoa;
+            break;
+#endif
+        default:
+#ifndef EMBEDDED
+            log_error("ERROR: invalid run loop type %u selected!\n", type);
+            exit(10);
+#endif
+            break;
+    }
+    the_run_loop->init();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/run_loop_embedded.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,218 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  run_loop_embedded.c
+ *
+ *  For this run loop, we assume that there's no global way to wait for a list
+ *  of data sources to get ready. Instead, each data source has to queried
+ *  individually. Calling ds->isReady() before calling ds->process() doesn't 
+ *  make sense, so we just poll each data source round robin.
+ *
+ *  To support an idle state, where an MCU could go to sleep, the process function
+ *  has to return if it has to called again as soon as possible
+ *
+ *  After calling process() on every data source and evaluating the pending timers,
+ *  the idle hook gets called if no data source did indicate that it needs to be
+ *  called right away.
+ *
+ */
+
+
+#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"
+
+#include <stddef.h> // NULL
+
+// the run loop
+static linked_list_t data_sources;
+
+static linked_list_t timers;
+
+#ifdef HAVE_TICK
+static uint32_t system_ticks;
+#endif
+
+static int trigger_event_received = 0;
+
+/**
+ * trigger run loop iteration
+ */
+void embedded_trigger(void){
+    trigger_event_received = 1;
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void embedded_add_data_source(data_source_t *ds){
+    linked_list_add(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int embedded_remove_data_source(data_source_t *ds){
+    return linked_list_remove(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void embedded_add_timer(timer_source_t *ts){
+#ifdef HAVE_TICK
+    linked_item_t *it;
+    for (it = (linked_item_t *) &timers; it->next ; it = it->next){
+        if (ts->timeout < ((timer_source_t *) it->next)->timeout) {
+            break;
+        }
+    }
+    ts->item.next = it->next;
+    it->next = (linked_item_t *) ts;
+    // log_info("Added timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    // embedded_dump_timer();
+#endif
+}
+
+/**
+ * Remove timer from run loop
+ */
+int embedded_remove_timer(timer_source_t *ts){
+#ifdef HAVE_TICK    
+    // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    return linked_list_remove(&timers, (linked_item_t *) ts);
+#else
+    return 0;
+#endif
+}
+
+void embedded_dump_timer(void){
+#ifdef HAVE_TICK
+#ifdef ENABLE_LOG_INFO 
+    linked_item_t *it;
+    int i = 0;
+    for (it = (linked_item_t *) timers; it ; it = it->next){
+        timer_source_t *ts = (timer_source_t*) it;
+        log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout);
+    }
+#endif
+#endif
+}
+
+/**
+ * Execute run_loop
+ */
+void embedded_execute(void) {
+    data_source_t *ds;
+
+    while (1) {
+
+        // process data sources
+        data_source_t *next;
+        for (ds = (data_source_t *) data_sources; ds != NULL ; ds = next){
+            next = (data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
+            ds->process(ds);
+        }
+        
+#ifdef HAVE_TICK
+        // process timers
+        while (timers) {
+            timer_source_t *ts = (timer_source_t *) timers;
+            if (ts->timeout > system_ticks) break;
+            run_loop_remove_timer(ts);
+            ts->process(ts);
+        }
+#endif
+        
+        // disable IRQs and check if run loop iteration has been requested. if not, go to sleep
+        hal_cpu_disable_irqs();
+        if (trigger_event_received){
+            hal_cpu_enable_irqs_and_sleep();
+            continue;
+        }
+        hal_cpu_enable_irqs();
+    }
+}
+
+#ifdef HAVE_TICK
+static void embedded_tick_handler(void){
+    system_ticks++;
+    trigger_event_received = 1;
+}
+
+uint32_t embedded_get_ticks(void){
+    return system_ticks;
+}
+
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms){
+    return time_in_ms / hal_tick_get_tick_period_in_ms();
+}
+
+// set timer
+void run_loop_set_timer(timer_source_t *ts, uint32_t timeout_in_ms){
+    uint32_t ticks = embedded_ticks_for_ms(timeout_in_ms);
+    if (ticks == 0) ticks++;
+    ts->timeout = system_ticks + ticks; 
+}
+#endif
+
+void embedded_init(void){
+
+    data_sources = NULL;
+
+#ifdef HAVE_TICK
+    timers = NULL;
+    system_ticks = 0;
+    hal_tick_init();
+    hal_tick_set_handler(&embedded_tick_handler);
+#endif
+}
+
+extern const run_loop_t run_loop_embedded;
+const run_loop_t run_loop_embedded = {
+    &embedded_init,
+    &embedded_add_data_source,
+    &embedded_remove_data_source,
+    &embedded_add_timer,
+    &embedded_remove_timer,
+    &embedded_execute,
+    &embedded_dump_timer
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/run_loop_private.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,68 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  run_loop_private.h
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#pragma once
+
+#include "btstack/run_loop.h"
+
+#ifdef HAVE_TIME
+#include <sys/time.h>
+
+// compare timeval or timers - NULL is assumed to be before the Big Bang
+int run_loop_timeval_compare(struct timeval *a, struct timeval *b);
+int run_loop_timer_compare(timer_source_t *a, timer_source_t *b);
+
+#endif
+
+// 
+void run_loop_timer_dump(void);
+
+// 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);
+} run_loop_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/utils.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,184 @@
+/*
+ * 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
+ *
+ */
+
+/*
+ *  utils.c
+ *
+ *  General utility functions
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include "config.h"
+#include <btstack/utils.h>
+#include <stdio.h>
+#include "debug.h"
+
+void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
+    buffer[pos++] = value;
+    buffer[pos++] = value >> 8;
+}
+
+void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){
+    buffer[pos++] = value;
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value >> 16;
+    buffer[pos++] = value >> 24;
+}
+
+void net_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value;
+}
+
+void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){
+    buffer[pos++] = value >> 24;
+    buffer[pos++] = value >> 16;
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value;
+}
+
+void bt_flip_addr(bd_addr_t dest, bd_addr_t src){
+    dest[0] = src[5];
+    dest[1] = src[4];
+    dest[2] = src[3];
+    dest[3] = src[2];
+    dest[4] = src[1];
+    dest[5] = src[0];
+}
+
+void hexdump(void *data, int size){
+    int i;
+    for (i=0; i<size;i++){
+        log_info("%02X ", ((uint8_t *)data)[i]);
+    }
+    log_info("\n");
+}
+
+void printUUID(uint8_t *uuid) {
+    log_info("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+           uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+           uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+static char bd_addr_to_str_buffer[6*3];  // 12:45:78:01:34:67\0
+char * bd_addr_to_str(bd_addr_t addr){
+    sprintf(bd_addr_to_str_buffer, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+    return (char *) bd_addr_to_str_buffer;
+}
+
+void print_bd_addr( bd_addr_t addr){
+    log_info("%s", bd_addr_to_str(addr));
+}
+
+#ifndef EMBEDDED
+int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr){
+	unsigned int bd_addr_buffer[BD_ADDR_LEN];  //for sscanf, integer needed
+	// reset result buffer
+	int i;
+    for (i = 0; i < BD_ADDR_LEN; i++) {
+        bd_addr_buffer[i] = 0;
+    }
+    
+	// parse
+    int result = sscanf( (char *) addr_string, "%2x:%2x:%2x:%2x:%2x:%2x", &bd_addr_buffer[0], &bd_addr_buffer[1], &bd_addr_buffer[2],
+						&bd_addr_buffer[3], &bd_addr_buffer[4], &bd_addr_buffer[5]);
+	// store
+	if (result == 6){
+		for (i = 0; i < BD_ADDR_LEN; i++) {
+			addr[i] = (uint8_t) bd_addr_buffer[i];
+		}
+	}
+	return (result == 6);
+}
+#endif
+
+/*  
+ * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
+ */
+static const uint8_t crc8table[256] = {    /* reversed, 8-bit, poly=0x07 */
+    0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+    0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+    0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+    0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+    0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+    0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+    0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+    0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+    0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+    0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+    0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+    0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+    0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+    0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+    0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+    0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define CRC8_INIT  0xFF          // Initial FCS value 
+#define CRC8_OK    0xCF          // Good final FCS value 
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8(uint8_t *data, uint16_t len)
+{
+    uint16_t count;
+    uint8_t crc = CRC8_INIT;
+    for (count = 0; count < len; count++)
+        crc = crc8table[crc ^ data[count]];
+    return crc;
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum)
+{
+    uint8_t crc;
+    
+    crc = crc8(data, len);
+    
+    crc = crc8table[crc ^ check_sum];
+    if (crc == CRC8_OK) 
+        return 0;               /* Valid */
+    else 
+        return 1;               /* Failed */
+    
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_calc(uint8_t *data, uint16_t len)
+{
+    /* Ones complement */
+    return 0xFF - crc8(data, len);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem.lib	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/SomeRandomBloke/code/FatFileSystem/#5baba5d5b728
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TB6612FNG2.lib	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/jksoft/code/TB6612FNG2/#051a7ecff13e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc/msc.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,390 @@
+#include "msc.h"
+//#define __DEBUG
+#include "mydbg.h"
+#include "Utils.h"
+
+//#define WRITE_PROTECT
+
+msc::msc(const char* name, int drive): FATFileSystem(name)
+{
+    DBG("drive=%d\n", drive);
+    m_name = name;
+    m_drive = drive;
+    DBG_ASSERT(sizeof(CBW) == 31);
+    DBG_ASSERT(sizeof(CSW) == 13);
+    m_numBlocks = 0;
+    m_BlockSize = 0;
+    m_lun = 0;
+    m_interface = 0;
+    m_pDev = NULL;
+    m_pEpBulkIn = NULL;
+    m_pEpBulkOut = NULL;
+}
+
+int msc::disk_initialize()
+{
+    DBG("m_BlockSize=%d\n", m_BlockSize);
+    if (m_BlockSize != 512) {
+        return 1;
+    }
+    return 0;    
+}
+
+int msc::disk_write(const char *buffer, int block_number)
+{
+    DBG("buffer=%p block_number=%d\n", buffer, block_number);
+    int ret = MS_BulkSend(block_number, 1, (uint8_t*)buffer);
+    if (ret >= 0) {
+        return 0;
+    }
+    return 1;
+}
+
+int msc::disk_read(char *buffer, int block_number)
+{
+    DBG("buffer=%p block_number=%d\n", buffer, block_number);
+    int ret = MS_BulkRecv(block_number, 1, (uint8_t*)buffer);
+    if (ret >= 0) {
+        return 0;
+    }
+    return 1;
+}    
+
+int msc::disk_status()
+{
+    DBG("\n");
+    return 0;
+}
+
+int msc::disk_sync()
+{
+    DBG("\n");
+    return 0;
+}
+
+int msc::disk_sectors()
+{
+    DBG("m_numBlocks=%d\n", m_numBlocks);
+    return m_numBlocks;
+}
+
+int msc::setup(int timeout)
+{
+    for(int i = 0; i < 2; i++) {
+        m_pDev = m_pHost->getDeviceByClass(0x08, m_drive); // USB Mass Storage Class
+        if (m_pDev || i > 0) {
+            break;
+        }
+        UsbErr rc = Usb_poll();
+        if (rc == USBERR_PROCESSING) {
+            VERBOSE("%p USBERR_PROCESSING\n", this);
+            return -1;
+        }
+    }
+    DBG("m_pDev=%p\n", m_pDev);
+    if (m_pDev == NULL) {
+        VERBOSE("%p MSC DISK(%d) NOT FOUND\n", this, m_drive);
+        return -1;
+    }
+    DBG_ASSERT(m_pDev);
+
+    ParseConfiguration();
+    
+    GetMaxLUN();
+
+    int retry = 0;
+    Timer t;
+    t.start();
+    t.reset();
+    while(t.read_ms() < timeout) {
+        DBG("retry=%d t=%d\n", retry, t.read_ms());
+        if (retry > 80) {
+            return -1;
+        }
+        int rc = TestUnitReady();
+        DBG("TestUnitReady(): %d\n", rc);
+        if (rc == USBERR_OK) {
+            DBG("m_CSW.bCSWStatus: %02X\n", m_CSW.bCSWStatus);
+            if (m_CSW.bCSWStatus == 0x00) {
+                break;
+            }
+        }
+        GetSenseInfo();
+        retry++;
+        wait_ms(50);
+    }
+    if (t.read_ms() >= timeout) {
+        return -1;
+    }
+    ReadCapacity();
+    Inquire();
+    return 0;
+}
+void msc::_test()
+{
+    ReadCapacity();
+
+    char buf[512];
+    for(int block = 0; block < m_numBlocks; block++) {
+    DBG("block=%d\n", block);
+        disk_read(buf, block);    
+    }
+    exit(1);
+}
+
+int msc::ParseConfiguration()
+{
+  UsbErr rc;
+  uint8_t ConfigDesc[9];
+  int index = 0;
+  DBG_ASSERT(m_pDev);
+  rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("ConfigDescriptor 9bytes", ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(ConfigDesc[0] == 9);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  int wTotalLength = *((uint16_t*)&ConfigDesc[2]);
+  DBG("TotalLength: %d\n", wTotalLength);
+  int bConfigValue = ConfigDesc[5];
+  DBG_ASSERT(bConfigValue == 1);
+  DBG("ConfigValue: %d\n", bConfigValue);
+  DBG("MaxPower: %d mA\n", ConfigDesc[8]*2);   
+
+  uint8_t* buf = new uint8_t[wTotalLength];
+  DBG_ASSERT(buf);
+  rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, wTotalLength);
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  for (int pos = 0; pos < wTotalLength; pos += buf[pos]) {
+      DBG_BYTES("CFG", buf+pos, buf[pos]);
+      int type = buf[pos+1];
+      if (USB_DESCRIPTOR_TYPE_INTERFACE == type) { // 0x04
+        DBG("InterfaceNumber: %d\n", buf[pos+2]);
+        DBG("AlternateSetting: %d\n", buf[pos+3]);
+        DBG("NumEndpoint: %d\n", buf[pos+4]);
+        DBG("InterfaceClass: %02X\n", buf[pos+5]);
+        DBG("InterfaceSubClass: %02X\n", buf[pos+6]);
+        DBG("InterfaceProtocol: %02X\n", buf[pos+7]);
+        DBG_ASSERT(buf[pos+6] == 0x06); // SCSI
+        DBG_ASSERT(buf[pos+7] == 0x50); // bulk only
+      } 
+      if (USB_DESCRIPTOR_TYPE_ENDPOINT == type) {
+          DBG_ASSERT(buf[pos] == 7);
+          uint8_t att = buf[pos+3];
+          if (att == 2) { // bulk
+              uint8_t ep = buf[pos+2];
+              bool dir = ep & 0x80; // true=IN
+              uint16_t size = LE16(buf+pos+4);
+              DBG("EndpointAddress: %02X\n", ep);
+              DBG("Attribute: %02X\n", att);
+              DBG("MaxPacketSize: %d\n", size); 
+              UsbEndpoint* pEp = new UsbEndpoint(m_pDev, ep, dir, USB_BULK, size);
+              DBG_ASSERT(pEp);
+              if (dir) {
+                  m_pEpBulkIn = pEp;
+              } else {
+                  m_pEpBulkOut = pEp;
+              } 
+          }
+      }
+  }
+  delete[] buf;
+  DBG_ASSERT(m_pEpBulkIn);
+  DBG_ASSERT(m_pEpBulkOut);
+  return 0;   
+}
+
+int msc::BulkOnlyMassStorageReset()
+{
+    DBG_ASSERT(m_pDev);
+    UsbErr rc = m_pDev->controlReceive(0x21, 0xff, 0x0000, m_interface, NULL, 0); 
+    DBG_ASSERT(rc == USBERR_OK);
+    return rc;
+}
+
+int msc::GetMaxLUN()
+{
+    DBG_ASSERT(m_interface == 0);
+    uint8_t temp[1];
+    DBG_ASSERT(m_pDev);
+    UsbErr rc = m_pDev->controlReceive(0xa1, 0xfe, 0x0000, m_interface, temp, sizeof(temp)); 
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GetMaxLUN", temp, sizeof(temp));
+    m_MaxLUN = temp[0];
+    DBG_ASSERT(m_MaxLUN <= 15);
+    return rc;
+}
+
+
+int msc::TestUnitReady()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00};
+    m_CBW.dCBWDataTraansferLength = 0;
+    m_CBW.bmCBWFlags = 0x00;
+    CommandTransport(cdb, sizeof(cdb));
+    StatusTransport();
+    return 0;
+}
+
+int msc::GetSenseInfo()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_REQUEST_SENSE, 0x00, 0x00, 0x00, 18, 0x00};
+    m_CBW.dCBWDataTraansferLength = 18;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[18];
+    _bulkRecv(buf, sizeof(buf));
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return 0;
+}
+
+int msc::ReadCapacity()
+{
+    const uint8_t cdb[10] = {SCSI_CMD_READ_CAPACITY, 0x00, 0x00, 0x00, 0x00, 
+                                               0x00, 0x00, 0x00, 0x00, 0x00};
+    m_CBW.dCBWDataTraansferLength = 8;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[8];
+    int rc = _bulkRecv(buf, sizeof(buf));
+    DBG_ASSERT(rc >= 0);
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+    
+    m_numBlocks = BE32(buf);
+    m_BlockSize = BE32(buf+4);
+    DBG("m_numBlocks=%d m_BlockSize=%d\n", m_numBlocks, m_BlockSize);
+    DBG_ASSERT(m_BlockSize == 512);
+    DBG_ASSERT(m_numBlocks > 0);
+    return 0;
+}
+
+int msc::Inquire()
+{
+    const uint8_t cdb[6] = {SCSI_CMD_INQUIRY, 0x00, 0x00, 0x00, 36, 0x00};
+    m_CBW.dCBWDataTraansferLength = 36;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    uint8_t buf[36];
+    _bulkRecv(buf, sizeof(buf));
+    DBG_HEX(buf, sizeof(buf));
+
+    StatusTransport();
+    return 0;
+}
+
+int msc::MS_BulkRecv(uint32_t block_number, int num_blocks, uint8_t* user_buffer)
+{
+    DBG_ASSERT(m_BlockSize == 512);
+    DBG_ASSERT(num_blocks == 1);
+    DBG_ASSERT(user_buffer);
+    uint8_t cdb[10] = {SCSI_CMD_READ_10, 0x00, 0x00, 0x00, 0x00, 
+                                   0x00, 0x00, 0x00, 0x00, 0x00};
+    BE32(block_number, cdb+2);
+    BE16(num_blocks, cdb+7);
+    uint32_t len = m_BlockSize * num_blocks;
+    DBG_ASSERT(len <= 512);
+    m_CBW.dCBWDataTraansferLength = len;
+    m_CBW.bmCBWFlags = 0x80; // data In
+    CommandTransport(cdb, sizeof(cdb));
+
+    int ret = _bulkRecv(user_buffer, len);
+    //DBG_HEX(user_buffer, len);
+
+    StatusTransport();
+    DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return ret;
+}
+
+int msc::MS_BulkSend(uint32_t block_number, int num_blocks, uint8_t* user_buffer)
+{
+#ifdef WRITE_PROTECT
+    return 0;
+#else
+    DBG_ASSERT(num_blocks == 1);
+    DBG_ASSERT(user_buffer);
+    uint8_t cdb[10] = {SCSI_CMD_WRITE_10, 0x00, 0x00, 0x00, 0x00, 
+                                    0x00, 0x00, 0x00, 0x00, 0x00};
+    BE32(block_number, cdb+2);
+    BE16(num_blocks, cdb+7);
+    uint32_t len = m_BlockSize * num_blocks;
+    DBG_ASSERT(len <= 512);
+    m_CBW.dCBWDataTraansferLength = len;
+    m_CBW.bmCBWFlags = 0x00; // data Out
+    CommandTransport(cdb, sizeof(cdb));
+
+    int ret = _bulkSend(user_buffer, len);
+    //DBG_HEX(user_buffer, len);
+
+    StatusTransport();
+    DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+    return ret;
+#endif //WRITE_PROTECT    
+}
+
+int msc::CommandTransport(const uint8_t* cdb, int size)
+{
+    DBG_ASSERT(cdb);
+    DBG_ASSERT(size >= 6);
+    DBG_ASSERT(size <= 16);
+    m_CBW.bCBWLUN = m_lun;
+    m_CBW.bCBWCBLength = size;
+    memcpy(m_CBW.CBWCB, cdb, size);
+
+    m_CBW.dCBWSignature = 0x43425355;
+    m_CBW.dCBWTag = m_tag++;
+    m_CBW.bCBWLUN = 0;
+    //DBG_HEX((uint8_t*)&m_CBW, sizeof(CBW));
+    int rc = _bulkSend((uint8_t*)&m_CBW, sizeof(CBW));
+    return rc;
+}
+
+int msc::StatusTransport()
+{
+    DBG_ASSERT(sizeof(CSW) == 13);
+    int rc = _bulkRecv((uint8_t*)&m_CSW, sizeof(CSW));
+    //DBG_HEX((uint8_t*)&m_CSW, sizeof(CSW));
+    DBG_ASSERT(m_CSW.dCSWSignature == 0x53425355);
+    DBG_ASSERT(m_CSW.dCSWTag == m_CBW.dCBWTag);
+    DBG_ASSERT(m_CSW.dCSWDataResidue == 0);
+    return rc;
+}
+
+int msc::_bulkRecv(uint8_t* buf, int size)
+{
+    UsbErr rc = m_pEpBulkIn->transfer(buf, size);
+    DBG_ASSERT(rc == USBERR_PROCESSING);
+    while(m_pEpBulkIn->status() == USBERR_PROCESSING){
+        wait_us(1);
+    }
+    int ret = m_pEpBulkIn->status();
+    if (ret >= 0) {
+        return ret;
+    }
+    DBG("buf=%p size=%d ret=%d\n", buf, size, ret);
+    return ret;
+}
+
+int msc::_bulkSend(uint8_t* buf, int size)
+{
+    DBG_ASSERT(m_pEpBulkOut);
+    UsbErr rc = m_pEpBulkOut->transfer(buf, size);
+    DBG_ASSERT(rc == USBERR_PROCESSING);
+    while(m_pEpBulkOut->status() == USBERR_PROCESSING){
+        wait_us(1);
+    }
+    int ret = m_pEpBulkOut->status();
+    if (ret >= 0) {
+        return ret;
+    }
+    DBG("buf=%p size=%d ret=%d\n", buf, size, ret);
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc/msc.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,75 @@
+#ifndef MSC_H
+#define MSC_H
+#include "UsbHostMgr.h"
+#include "UsbEndpoint.h"
+#include "UsbBaseClass.h"
+#include "FATFileSystem.h"
+
+#define  SCSI_CMD_REQUEST_SENSE      0x03
+#define  SCSI_CMD_TEST_UNIT_READY    0x00
+#define  SCSI_CMD_INQUIRY            0x12
+#define  SCSI_CMD_READ_10            0x28
+#define  SCSI_CMD_READ_CAPACITY      0x25
+#define  SCSI_CMD_WRITE_10           0x2A
+
+#pragma pack(push,1)
+typedef struct stcbw {
+    uint32_t dCBWSignature;
+    uint32_t dCBWTag;
+    uint32_t dCBWDataTraansferLength;
+    uint8_t bmCBWFlags;
+    uint8_t bCBWLUN;
+    uint8_t bCBWCBLength;
+    uint8_t CBWCB[16];
+} CBW;
+
+typedef struct stcsw {
+    uint32_t dCSWSignature;
+    uint32_t dCSWTag;
+    uint32_t dCSWDataResidue;
+    uint8_t  bCSWStatus;
+} CSW;
+#pragma pack(pop)
+
+class msc : public FATFileSystem, public UsbBaseClass {
+public:
+    msc(const char* name = NULL, int drive = 0);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+    int setup(int timeout = 9000);
+    void _test();
+private:
+    int ParseConfiguration();
+    int BulkOnlyMassStorageReset();
+    int GetMaxLUN();
+    int ReadCapacity();
+    int GetSenseInfo();
+    int TestUnitReady();
+    int Inquire();
+    int MS_BulkRecv(uint32_t block_number, int num_blocks, uint8_t* user_buffer);
+    int MS_BulkSend(uint32_t block_number, int num_blocks, uint8_t* user_buffer);
+    int CommandTransport(const uint8_t* cdb, int size);
+    int StatusTransport();
+    int _bulkRecv(uint8_t* buf, int size);
+    int _bulkSend(uint8_t* buf, int size);
+    const char* m_name;
+    int m_drive;
+    uint32_t m_numBlocks;
+    int m_BlockSize;
+    int m_lun;
+    int m_MaxLUN;
+    int m_interface;
+    uint32_t m_tag;
+    CBW m_CBW;
+    CSW m_CSW;
+    UsbDevice* m_pDev;
+    UsbEndpoint* m_pEpBulkIn;
+    UsbEndpoint* m_pEpBulkOut;
+};
+
+#endif // MSC_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbBaseClass.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,38 @@
+#include "UsbBaseClass.h"
+//#define __DEBUG
+#include "mydbg.h"
+
+UsbBaseClass::UsbBaseClass()
+{
+    if (m_pHost == NULL) {
+        m_pHost = new UsbHostMgr;
+        DBG_ASSERT(m_pHost);
+        m_pHost->init();
+    }
+    DBG("m_pHost=%p\n", m_pHost);
+}
+
+UsbErr UsbBaseClass::Usb_poll(int timeout, int timeout2)
+{
+    DBG("%p %d %d\n", this, timeout, timeout2);
+    Timer t;
+    t.reset();
+    t.start();
+    Timer t2;
+    t2.reset();
+    t2.start();
+    while(t.read_ms() < timeout) {
+        UsbErr rc = m_pHost->poll();
+        if (rc == USBERR_PROCESSING) {
+            t2.reset();
+        }
+        if (t2.read_ms() > timeout2) {
+            DBG("%p t=%d\n", this, t.read_ms());
+            return USBERR_OK;
+        }
+        wait_ms(50);
+    }
+    return USBERR_PROCESSING;
+}
+
+UsbHostMgr* UsbBaseClass::m_pHost = NULL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbBaseClass.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,13 @@
+#ifndef _USB_BASE_CLASS_H_
+#define _USB_BASE_CLASS_H_
+#include "UsbHostMgr.h"
+
+class UsbBaseClass {
+public:
+    UsbBaseClass();
+protected:
+    UsbErr Usb_poll(int timeout = 15000, int timeout2 = 2000);
+    static UsbHostMgr* m_pHost;
+};
+
+#endif //_USB_BASE_CLASS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbDevice.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,400 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UsbDevice.h"
+//#define __DEBUG
+#include "mydbg.h"
+
+UsbDevice::UsbDevice( UsbHostMgr* pMgr, int hub, int port, int addr ) : m_pControlEp(NULL), /*m_controlEp( this, 0x00, false, USB_CONTROL, 8 ),*/
+m_pMgr(pMgr), m_connected(false), m_enumerated(false), m_hub(hub), m_port(port), m_addr(addr), m_refs(0),
+m_vid(0), m_pid(0)
+{
+    m_DeviceClass    = 0x00;
+    m_InterfaceClass = 0x00;
+}
+
+UsbDevice::~UsbDevice()
+{
+    DBG_ASSERT(0);
+
+  if(m_pControlEp)
+    delete m_pControlEp;
+}
+
+UsbErr UsbDevice::enumerate()
+{
+  VERBOSE("Hub: %d Port: %d\n", m_hub, m_port);
+  UsbErr rc;
+  DBG("%p m_hub=%d m_port=%d\n", this, m_hub, m_port);
+  DBG_ASSERT(m_pMgr);
+  m_pMgr->resetPort(m_hub, m_port);
+
+  wait_ms(400);
+
+  uint8_t temp[8];
+  DBG_ASSERT(m_pControlEp == NULL);   
+  m_pControlEp = new UsbEndpoint( this, 0x00, false, USB_CONTROL, sizeof(temp), 0 );
+  DBG_ASSERT(m_pControlEp);
+  //EDCtrl->Control = 8 << 16;/* Put max pkt size = 8              */
+  /* Read first 8 bytes of device desc */
+  DBG_ASSERT(sizeof(temp) >= 8);
+  //rc = controlReceive(
+  //    USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, 
+  //    (USB_DESCRIPTOR_TYPE_DEVICE << 8) |(0), 0, temp, sizeof(temp));
+  //DBG_ASSERT(rc == USBERR_OK);
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_DEVICE, 0, temp, sizeof(temp));
+  if (rc != USBERR_OK) {
+      DBG("rc=%d\n", rc);
+      DBG_ASSERT(rc == USBERR_OK);
+      return rc;
+  }
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("DeviceDescriptor first 8 bytes", temp, sizeof(temp));
+  DBG_ASSERT(temp[0] == 18);   // bLength
+  DBG_ASSERT(temp[1] == 0x01); // bDescriptType
+  if (rc)
+  {
+    DBG("RC=%d",rc);
+    return (rc);
+  }
+  uint8_t bMaxPacketSize = temp[7];
+  DBG_ASSERT(bMaxPacketSize >= 8);
+  DBG("Got descriptor, max ep size is %d\n", bMaxPacketSize);
+  
+  m_pControlEp->updateSize(bMaxPacketSize); /* Get max pkt size of endpoint 0    */
+  rc = controlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, SET_ADDRESS, m_addr, 0, NULL, 0); /* Set the device address to m_addr       */
+  DBG_ASSERT(rc == USBERR_OK);
+  if (rc)
+  {
+  //  PRINT_Err(rc);
+    return (rc);
+  }
+  wait_ms(2);
+  //EDCtrl->Control = (EDCtrl->Control) | 1; /* Modify control pipe with address 1 */
+  
+  //Update address
+  m_pControlEp->updateAddr(m_addr);
+  DBG("Ep addr is now %d", m_addr);
+  /**/
+  
+  //rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_DEVICE, 0, TDBuffer, 17); //Read full device descriptor
+  //rc = controlReceive(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, 
+  //    (USB_DESCRIPTOR_TYPE_DEVICE << 8)|(0), 0, 
+  //    m_controlDataBuf, 17);
+  uint8_t DeviceDesc[18];
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_DEVICE, 0, DeviceDesc, sizeof(DeviceDesc));
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("DeviceDescriptor", DeviceDesc, sizeof(DeviceDesc));
+  DBG_ASSERT(DeviceDesc[0] == 18);
+  DBG_ASSERT(DeviceDesc[1] == 0x01);
+  DBG_ASSERT(DeviceDesc[17] == 1); // bNumConfiguration
+  if (rc)
+  {
+    //PRINT_Err(rc);
+    return (rc);
+  }
+
+  /*
+  rc = SerialCheckVidPid();
+  if (rc != OK) {
+    PRINT_Err(rc);
+    return (rc);
+  }
+  */
+  /**/
+  m_DeviceClass = DeviceDesc[4];
+  VERBOSE("DeviceClass: %02X\n", m_DeviceClass);
+ 
+  m_vid = *((uint16_t*)&DeviceDesc[8]);
+  m_pid = *((uint16_t*)&DeviceDesc[10]);
+  VERBOSE("Vender: %04X\n", m_vid);
+  VERBOSE("Product: %04X\n", m_pid);
+  int iManufacture = DeviceDesc[14];
+  if (iManufacture) {
+    char str[64];
+    rc = GetString(iManufacture, str, sizeof(str)); 
+    DBG_ASSERT(rc == USBERR_OK);
+    VERBOSE("Manufacture: %s\n", str);
+  }
+  int iProduct = DeviceDesc[15];
+  if (iProduct) {
+    char str[64];
+    rc = GetString(iProduct, str, sizeof(str)); 
+    DBG_ASSERT(rc == USBERR_OK);
+    VERBOSE("Product: %s\n", str);
+  }
+  if (DeviceDesc[4] == 0x09) { // Hub
+      return hub_init();
+  }
+  
+  uint8_t ConfigDesc[9];
+  int index = 0;
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("ConfigDescriptor 9bytes", ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(ConfigDesc[0] == 9);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  int wTotalLength = *((uint16_t*)&ConfigDesc[2]);
+  DBG("TotalLength: %d\n", wTotalLength);
+  int bConfigValue = ConfigDesc[5];
+  DBG_ASSERT(bConfigValue == 1);
+  DBG("ConfigValue: %d\n", bConfigValue);
+  DBG("MaxPower: %d mA\n", ConfigDesc[8]*2);   
+
+  uint8_t* buf = new uint8_t[wTotalLength];
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, wTotalLength);
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  int pos = 0;
+  while(pos < wTotalLength) {
+      DBG_BYTES("", buf+pos, buf[pos]);
+      if (buf[pos+1] == 4) { // interface ?
+          m_InterfaceClass = buf[pos+5];
+          VERBOSE("InterfaceClass: %02X\n", m_InterfaceClass);
+          break;
+      }
+      pos += buf[pos];
+  }
+  delete[] buf;
+  
+  rc = setConfiguration(1);
+  DBG_ASSERT(rc == USBERR_OK);
+  if (rc)
+  {
+   // PRINT_Err(rc);
+   return rc;
+  }
+  wait_ms(100);/* Some devices may require this delay */
+  
+  m_enumerated = true;
+  return USBERR_OK;
+}
+
+bool UsbDevice::connected()
+{
+  return m_connected;
+}
+
+bool UsbDevice::enumerated()
+{
+  return m_enumerated;
+}
+
+int UsbDevice::getPid()
+{
+  return m_pid;
+}
+
+int UsbDevice::getVid()
+{
+  return m_vid;
+}
+#if 0
+UsbErr UsbDevice::getConfigurationDescriptor(int config, uint8_t** pBuf)
+{
+  DBG_ASSERT(m_controlDataBuf);
+  //For now olny one config
+  *pBuf = m_controlDataBuf;
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::getInterfaceDescriptor(int config, int item, uint8_t** pBuf)
+{
+  DBG_ASSERT(m_controlDataBuf);
+  byte* desc_ptr = m_controlDataBuf;
+
+/*  if (desc_ptr[1] != USB_DESCRIPTOR_TYPE_CONFIGURATION)
+  {    
+    return USBERR_BADCONFIG;
+  }*/
+  DBG_ASSERT(m_controlDataBuf);
+  if(item>=m_controlDataBuf[4])//Interfaces count
+    return USBERR_NOTFOUND;
+  
+  desc_ptr += desc_ptr[0];
+  
+  *pBuf = NULL;
+  
+  while (desc_ptr < m_controlDataBuf + *((uint16_t*)&m_controlDataBuf[2]))
+  {
+
+    switch (desc_ptr[1]) {
+      case USB_DESCRIPTOR_TYPE_INTERFACE: 
+        if(desc_ptr[2] == item)
+        {
+          *pBuf = desc_ptr;
+          return USBERR_OK;
+        }
+        desc_ptr += desc_ptr[0]; // Move to next descriptor start
+        break;
+    }
+      
+  }
+  
+  if(*pBuf == NULL)
+    return USBERR_NOTFOUND;
+    
+  return USBERR_OK;
+}
+#endif
+
+UsbErr UsbDevice::setConfiguration(int config)
+{
+  DBG("config=%d\n", config);
+  DBG_ASSERT(config == 1);    
+  UsbErr rc = controlSend(
+          USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, // 0x00 
+          SET_CONFIGURATION, config, 0, 0, 0);
+  return rc;
+}
+
+UsbErr UsbDevice::controlSend(byte requestType, byte request, word value, word index, const byte* buf, int len)
+{
+  UsbErr rc;
+  fillControlBuf(requestType, request, value, index, len);
+  DBG_ASSERT(m_pControlEp);
+  m_pControlEp->setNextToken(TD_SETUP);
+  rc = m_pControlEp->transfer(m_controlBuf, 8);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  if(len)
+  {
+    m_pControlEp->setNextToken(TD_OUT);
+    rc = m_pControlEp->transfer((byte*)buf, len);
+    while(m_pControlEp->status() == USBERR_PROCESSING);
+    rc = (UsbErr) MIN(0, m_pControlEp->status());
+    if(rc)
+      return rc;
+  }
+  m_pControlEp->setNextToken(TD_IN);
+  rc = m_pControlEp->transfer(NULL, 0);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::controlReceive(byte requestType, byte request, word value, word index, const byte* buf, int len)
+{
+  DBG("buf=%p len=%d\n", buf, len);
+  UsbErr rc;
+  fillControlBuf(requestType, request, value, index, len);
+  DBG_ASSERT(m_pControlEp);
+  m_pControlEp->setNextToken(TD_SETUP);
+  rc = m_pControlEp->transfer(m_controlBuf, 8);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  if(len)
+  {
+    m_pControlEp->setNextToken(TD_IN);
+    rc = m_pControlEp->transfer( (byte*) buf, len);
+    while(m_pControlEp->status() == USBERR_PROCESSING);
+    rc = (UsbErr) MIN(0, m_pControlEp->status());
+    if(rc)
+      return rc;
+  }
+  m_pControlEp->setNextToken(TD_OUT);
+  rc = m_pControlEp->transfer(NULL, 0);
+  while(m_pControlEp->status() == USBERR_PROCESSING);
+  rc = (UsbErr) MIN(0, m_pControlEp->status());
+  if(rc)
+    return rc;
+  return USBERR_OK;
+}
+
+UsbErr UsbDevice::GetDescriptor(int type, int index, const byte* buf, int len)
+{
+  DBG("type=%02X\n", type);
+  return controlReceive(
+      USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR, 
+      (type << 8) |(index), 0, buf, len);
+
+}
+
+UsbErr UsbDevice::GetString(int index, char* buf, int len)
+{
+  DBG("index=%d buf=%p len=%d\n", index, buf, len);
+  DBG_ASSERT(index >= 1);
+  uint8_t temp[4];
+  UsbErr rc;
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_STRING, 0, temp, sizeof(temp));
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("LANG_ID", temp, sizeof(temp));
+  DBG_ASSERT(temp[0] == 4);
+  DBG_ASSERT(temp[1] == 0x03);
+  
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_STRING, index, temp, 2);
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("length check", temp, 2);
+  if (temp[0] == 0x00 && temp[1] == 0x00) { // for pl2303
+      if (len > 0) {
+          strcpy(buf, "");
+      }
+      return rc;
+  }
+  DBG_ASSERT(temp[1] == 0x03);
+  int temp_len = temp[0];
+    
+  uint8_t* temp_buf = new uint8_t[temp_len];
+  DBG_ASSERT(temp_buf);
+  rc = GetDescriptor(USB_DESCRIPTOR_TYPE_STRING, index, temp_buf, temp_len);
+  DBG_ASSERT(rc == USBERR_OK);
+  temp_len = temp_buf[0];
+  DBG_HEX(temp_buf, temp_len);
+  int i = 0;
+  for(int pos = 2; pos < temp_len; pos+= 2) {
+    buf[i++] = temp_buf[pos];
+    DBG_ASSERT(i < len-1);
+  }
+  buf[i] = '\0';
+  delete[] temp_buf;
+  return rc;
+}
+
+UsbErr UsbDevice::SetInterfaceAlternate(int interface, int alternate)
+{
+    UsbErr rc = controlSend(
+              USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, 
+              SET_INTERFACE, alternate, interface, NULL, 0);
+    return rc;
+}
+
+void UsbDevice::fillControlBuf(byte requestType, byte request, word value, word index, int len)
+{
+#ifdef __BIG_ENDIAN
+  #error "Must implement BE to LE conv here"
+#endif
+  m_controlBuf[0] = requestType;
+  m_controlBuf[1] = request;
+  //We are in LE so it's fine
+  *((word*)&m_controlBuf[2]) = value;
+  *((word*)&m_controlBuf[4]) = index;
+  *((word*)&m_controlBuf[6]) = (word) len;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbDevice.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,99 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_DEVICE_H
+#define USB_DEVICE_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+#include "UsbEndpoint.h"
+#include "UsbHostMgr.h"
+
+class UsbHostMgr;
+class UsbEndpoint;
+
+class UsbDevice
+{
+protected:
+  UsbDevice( UsbHostMgr* pMgr, int hub, int port, int addr );
+  ~UsbDevice();
+
+  UsbErr enumerate();
+
+public: 
+  bool connected();
+  bool enumerated();
+  
+  int getPid();
+  int getVid();
+  
+  //UsbErr getConfigurationDescriptor(int config, uint8_t** pBuf);
+  //UsbErr getInterfaceDescriptor(int config, int item, uint8_t** pBuf);
+  
+  UsbErr setConfiguration(int config);
+
+  UsbErr controlSend(byte requestType, byte request, word value, word index, const byte* buf, int len);
+  UsbErr controlReceive(byte requestType, byte request, word value, word index, const byte* buf, int len);
+  UsbErr GetDescriptor(int type, int index, const byte* buf, int len);
+  UsbErr GetString(int index, char* buf, int len);
+  UsbErr SetInterfaceAlternate(int interface, int alternate);
+
+  uint8_t m_DeviceClass;
+  uint8_t m_InterfaceClass;
+
+protected:
+  void fillControlBuf(byte requestType, byte request, word value, word index, int len);
+private:
+  friend class UsbEndpoint;
+  friend class UsbHostMgr;
+  
+  UsbEndpoint* m_pControlEp;
+  
+  UsbHostMgr* m_pMgr;
+  
+  bool m_connected;
+  bool m_enumerated;
+  
+  int m_hub;
+  int m_port;
+  int m_addr;
+  
+  int m_refs;
+  
+  uint16_t m_vid;
+  uint16_t m_pid;
+  
+  byte m_controlBuf[8];//8
+  //byte m_controlDataBuf[/*128*/256];
+  
+  UsbErr hub_init();
+  UsbErr hub_poll();
+  UsbErr hub_PortReset(int port);
+  UsbErr SetPortFeature(int feature, int index);
+  UsbErr ClearPortFeature(int feature, int index);
+  UsbErr SetPortReset(int port);
+  UsbErr GetPortStatus(int port, uint8_t* buf, int size);
+  int m_hub_ports;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbDevice2.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,133 @@
+#include "UsbDevice.h"
+//#define __DEBUG
+#include "mydbg.h"
+
+#define PORT_RESET         4
+#define PORT_POWER         8
+#define C_PORT_CONNECTION 16
+#define C_PORT_RESET      20
+
+UsbErr UsbDevice::hub_init()
+{
+    UsbErr rc;
+    uint8_t buf[9];
+    rc = controlReceive(
+          USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_DEVICE, // 0xa0 
+          GET_DESCRIPTOR, 
+          (USB_DESCRIPTOR_TYPE_HUB << 8), 0, buf, sizeof(buf));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_ASSERT(buf[0] == 9);
+    DBG_ASSERT(buf[1] == 0x29);
+    DBG_BYTES("HUB DESCRIPTOR", buf, sizeof(buf));
+
+    m_hub_ports = buf[2];
+    VERBOSE("NbrPorts: %d\n", m_hub_ports);
+    int PwrOn2PwrGood = buf[5];
+    VERBOSE("PwrOn2PwrGood: %d %d ms\n", PwrOn2PwrGood, PwrOn2PwrGood*2);
+    VERBOSE("HubContrCurrent: %d\n", buf[6]);
+
+    rc = setConfiguration(1);    
+    DBG_ASSERT(rc == USBERR_OK);
+    
+    uint8_t status[4];
+    rc = controlReceive(
+          USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_DEVICE, // 0xa0 
+          GET_STATUS, 
+          0, 0, status, sizeof(status));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("HUB STATUS", status, sizeof(status));
+
+    for(int i = 1; i <= m_hub_ports; i++) {
+        rc = SetPortFeature(PORT_POWER, i);
+        DBG("PORT_POWER port=%d rc=%d\n", i, rc);
+        DBG_ASSERT(rc == USBERR_OK);
+        if (rc != USBERR_OK) {
+            return rc;
+        }
+    }
+    wait_ms(PwrOn2PwrGood*2);
+    
+    m_enumerated = true;
+    return USBERR_OK;
+}
+
+UsbErr UsbDevice::hub_poll()
+{
+    DBG("%p m_hub=%d m_port=%d m_addr=%d\n", this, m_hub, m_port, m_addr);
+    // check status
+    for(int port = 1; port <= m_hub_ports; port++) {
+        uint8_t status[4];
+        UsbErr rc = GetPortStatus(port, status, sizeof(status));
+        DBG_ASSERT(rc == USBERR_OK);
+        DBG("port=%d\n", port);
+        DBG_BYTES("STATUS", status, sizeof(status));
+        if (status[2] & 0x01) { // Connect Status Change, has changed
+            DBG_ASSERT(status[0] & 0x01);
+            ClearPortFeature(C_PORT_CONNECTION, port);
+            DBG_ASSERT(m_pMgr);
+            m_pMgr->onUsbDeviceConnected(m_addr, port);
+            return USBERR_PROCESSING;
+        }
+    }
+    return USBERR_OK;
+}
+
+UsbErr UsbDevice::hub_PortReset(int port)
+{
+    DBG("%p port=%d\n", this, port);
+    DBG_ASSERT(port >= 1);
+    SetPortReset(port);
+    // wait reset
+    for(int i = 0; i < 100; i++) {
+        uint8_t status[4];    
+        UsbErr rc = GetPortStatus(port, status, sizeof(status));
+        DBG_ASSERT(rc == USBERR_OK);
+        DBG_BYTES("RESET", status, sizeof(status));
+        if (status[2] & 0x10) { // Reset change , Reset complete
+            return USBERR_OK;
+        }
+        wait_ms(5);
+     }
+     return USBERR_ERROR;
+}
+
+UsbErr UsbDevice::SetPortFeature(int feature, int index)
+{
+    //DBG("feature=%d index=%d\n", feature, index);
+    UsbErr rc;
+    rc = controlSend(
+          USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_OTHER, 
+          SET_FEATURE, feature, index, 0, 0);
+    return rc;
+}
+
+UsbErr UsbDevice::ClearPortFeature(int feature, int index)
+{
+    UsbErr rc;
+    rc = controlSend(
+          USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_OTHER, 
+          CLEAR_FEATURE, feature, index, 0, 0);
+    return rc;
+}
+
+UsbErr UsbDevice::SetPortReset(int port)
+{
+    //DBG("port=%d\n", port);
+    UsbErr rc = SetPortFeature(PORT_RESET, port);
+    DBG_ASSERT(rc == USBERR_OK);
+    return rc;
+}
+
+UsbErr UsbDevice::GetPortStatus(int port, uint8_t* buf, int size)
+{
+    DBG_ASSERT(size == 4);
+    UsbErr rc;
+    //return USBControlTransfer(device,
+    //DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,
+    //GET_STATUS,0,port,(u8*)status,4);
+
+    rc = controlReceive(
+          USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_OTHER, 
+          GET_STATUS, 0, port, buf, sizeof(buf));
+    return rc;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbEndpoint.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,373 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "UsbEndpoint.h"
+#include "UsbDevice.h"
+#include "usb_mem.h"
+#include "Usb_td.h"
+#include "netCfg.h"
+#if NET_USB
+
+//#define __DEBUG
+//#define __DEBUG3
+//#include "dbg/dbg.h"
+#include "mydbg.h"
+
+UsbEndpoint::UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr /*= -1*/ ) 
+: m_pDevice(pDevice), m_result(true), m_status((int)USBERR_OK), m_len(0), m_pBufStartPtr(NULL),
+  m_pCbItem(NULL), m_pCbMeth(NULL)
+{
+  if (type == USB_ISO) {
+      UsbEndpoint_iso(pDevice, ep, dir, type, size, addr);
+      return;
+  }
+
+  m_pEd = (volatile HCED*)usb_get_ed();
+  DBG_ASSERT(m_pEd);
+  memset((void*)m_pEd, 0, sizeof(HCED));
+  
+  m_pTdHead = (volatile HCTD*)usb_get_td((uint32_t)this);
+  DBG_ASSERT(m_pTdHead);
+  m_pTdTail = (volatile HCTD*)usb_get_td((uint32_t)this);
+  DBG_ASSERT(m_pTdTail);
+  DBG("m_pEd    =%p\n", m_pEd);
+  DBG("m_pTdHead=%p\n", m_pTdHead);
+  DBG("m_pTdTail=%p\n", m_pTdTail);
+  
+  if(addr == -1)
+    addr = pDevice->m_addr;
+  
+  //Setup Ed
+  //printf("\r\n--Ep Setup--\r\n");
+  m_pEd->Control =  addr        |      /* USB address           */
+  ((ep & 0x7F) << 7)            |      /* Endpoint address      */
+  (type!=USB_CONTROL?((dir?2:1) << 11):0)             |      /* direction : Out = 1, 2 = In */
+  (size << 16);     /* MaxPkt Size           */
+  DBG3("m_pEd->Control=%08X\n", m_pEd->Control);
+  m_dir = dir;
+  m_setup = false;
+  m_type = type;
+  
+  m_pEd->TailTd = m_pEd->HeadTd = (uint32_t) m_pTdTail; //Empty TD list
+  
+  DBG("Before link\n");
+  
+  //printf("\r\n--Ep Reg--\r\n");
+  //Append Ed to Ed list
+  HCCA* hcca;
+  //volatile HCED* nextEd;
+  DBG("m_type=%d\n", m_type);
+  switch( m_type )
+  {
+  case USB_CONTROL:
+    m_pEd->Next = LPC_USB->HcControlHeadED;
+    LPC_USB->HcControlHeadED = (uint32_t)m_pEd;
+    return;
+
+  case USB_BULK:
+    m_pEd->Next = LPC_USB->HcBulkHeadED;
+    LPC_USB->HcBulkHeadED = (uint32_t)m_pEd;
+    return;
+
+  case USB_INT:
+    hcca = (HCCA*)usb_get_hcca();
+    m_pEd->Next = hcca->IntTable[0];
+    hcca->IntTable[0] = (uint32_t)m_pEd;
+    return;
+  
+  default:
+    DBG_ASSERT(0);
+  }
+}
+
+
+UsbEndpoint::~UsbEndpoint()
+{
+  DBG_ASSERT(0);
+
+  m_pEd->Control |= ED_SKIP; //Skip this Ep in queue
+
+  //Remove from queue
+  volatile HCED* prevEd;
+  HCCA* hcca;
+  switch( m_type )
+  {
+  case USB_CONTROL:
+    prevEd = (volatile HCED*) LPC_USB->HcControlHeadED;
+    break;
+  case USB_BULK:
+    prevEd = (volatile HCED*) LPC_USB->HcBulkHeadED;
+    break;
+  case USB_INT:
+    hcca = (HCCA*)usb_get_hcca();
+    prevEd = (volatile HCED*)hcca->IntTable[0];
+    break;
+  default:
+    DBG_ASSERT(0);
+  }
+  if( m_pEd == prevEd )
+  {
+    switch( m_type )
+    {
+    case USB_CONTROL:
+      LPC_USB->HcControlHeadED = m_pEd->Next;
+      break;
+    case USB_BULK:
+      LPC_USB->HcBulkHeadED = m_pEd->Next;
+      break;
+    case USB_INT:
+      hcca = (HCCA*)usb_get_hcca();
+      hcca->IntTable[0] = m_pEd->Next;
+      break;
+    default:
+      DBG_ASSERT(0);
+    }
+    LPC_USB->HcBulkHeadED = m_pEd->Next;
+  }
+  else
+  {
+    while( prevEd->Next != (uint32_t) m_pEd )
+    {
+      prevEd = (volatile HCED*) prevEd->Next;
+    }
+    prevEd->Next = m_pEd->Next;
+  }
+  
+  //
+  usb_free_ed((volatile byte*)m_pEd);
+  
+  usb_free_td((volatile byte*)m_pTdHead);
+  usb_free_td((volatile byte*)m_pTdTail);
+}
+
+void UsbEndpoint::setNextToken(uint32_t token) //Only for control Eps
+{
+  switch(token)
+  {
+    case TD_SETUP:
+      m_dir = false;
+      m_setup = true;
+      break;
+    case TD_IN:
+      m_dir = true;
+      m_setup = false;
+      break;
+    case TD_OUT:
+      m_dir = false;
+      m_setup = false;
+      break;
+  }
+}
+
+UsbErr UsbEndpoint::transfer(volatile uint8_t* buf, uint32_t len)
+{
+  DBG("buf=%p\n", buf);
+  if(!m_result)
+    return USBERR_BUSY; //The previous trasnfer is not completed 
+    //FIXME: We should be able to queue the next transfer, still needs to be implemented
+  
+  if( !m_pDevice->connected() )
+    return USBERR_DISCONNECTED;
+  
+  m_result = false;
+  
+  volatile uint32_t token = (m_setup?TD_SETUP:(m_dir?TD_IN:TD_OUT));
+
+  volatile uint32_t td_toggle;
+  if (m_type == USB_CONTROL)
+  {
+    if (m_setup)
+    {
+      td_toggle = TD_TOGGLE_0;
+    }
+    else
+    {
+      td_toggle = TD_TOGGLE_1;
+    }
+  }
+  else
+  {
+    td_toggle = 0;
+  }
+
+  //Swap Tds
+  volatile HCTD* pTdSwap;
+  pTdSwap = m_pTdTail;
+  m_pTdTail = m_pTdHead;
+  m_pTdHead = pTdSwap;
+
+  m_pTdHead->Control = (TD_ROUNDING    |
+                       token           |
+                       TD_DELAY_INT(0) |//7
+                       td_toggle       |
+                       TD_CC);
+
+  m_pTdTail->Control = 0;
+  m_pTdHead->CurrBufPtr   = (uint32_t) buf;
+  m_pBufStartPtr = buf;
+  m_pTdTail->CurrBufPtr   = 0;
+  m_pTdHead->Next         = (uint32_t) m_pTdTail;
+  m_pTdTail->Next         = 0;
+  m_pTdHead->BufEnd       = (uint32_t)(buf + (len - 1));
+  m_pTdTail->BufEnd       = 0;
+  
+  m_pEd->HeadTd  = (uint32_t)m_pTdHead | ((m_pEd->HeadTd) & 0x00000002); //Carry bit
+  m_pEd->TailTd  = (uint32_t)m_pTdTail;
+  
+  //DBG("m_pEd->HeadTd = %08x\n", m_pEd->HeadTd);
+
+  if(m_type == USB_CONTROL) {
+    LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF;
+    LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_CLE; //Enable control list
+  } else if (m_type == USB_BULK) { //USB_BULK
+    LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF;
+    LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_BLE; //Enable bulk list
+  } else if (m_type == USB_INT) { // USB_INT
+    LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_PLE; //Enable Periodic
+  } else { // USB_ISO
+    DBG_ASSERT(0);
+  }
+  
+  //m_done = false;
+  m_len = len;
+
+  return USBERR_PROCESSING;
+ 
+}
+
+int UsbEndpoint::status()
+{
+  if( !m_pDevice->connected() )
+  {
+    if(!m_result)
+      onCompletion();
+    m_result = true;
+    return (int)USBERR_DISCONNECTED;
+  }
+  else if( !m_result )
+  { 
+    return (int)USBERR_PROCESSING;
+  }
+  /*else if( m_done )
+  {
+    return (int)USBERR_OK;
+  }*/
+  else
+  {
+    return m_status;
+  }
+}
+
+void UsbEndpoint::updateAddr(int addr)
+{
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+  m_pEd->Control &= ~0x7F;
+  m_pEd->Control |= addr;
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+}
+
+void UsbEndpoint::updateSize(uint16_t size)
+{
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+  m_pEd->Control &= ~0x3FF0000;
+  m_pEd->Control |= (size << 16);
+  DBG("m_pEd->Control = %08x\n", m_pEd->Control);
+}
+
+#if 0 //For doc only
+template <class T>
+void UsbEndpoint::setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
+{
+  m_pCbItem = (CDummy*) pCbItem;
+  m_pCbMeth = (void (CDummy::*)()) pCbMeth;
+}
+#endif
+
+void UsbEndpoint::onCompletion()
+{
+  DBG_ASSERT(m_type != USB_ISO);
+  DBG_ASSERT(m_pTdHead);
+  //DBG("Transfer completed\n");
+  if( m_pTdHead->Control >> 28  )
+  {
+    DBG("TD Failed with condition code %01x\n", m_pTdHead->Control >> 28 );
+    m_status = (int)USBERR_TDFAIL;
+  }
+  else if( m_pEd->HeadTd & 0x1 )
+  {
+    m_pEd->HeadTd = m_pEd->HeadTd & ~0x1;
+    DBG("\r\nHALTED!!\r\n");
+    m_status = (int)USBERR_HALTED;
+  }
+  else if( (m_pEd->HeadTd & ~0xF) == (uint32_t) m_pTdTail )
+  {
+    //Done
+    int len;
+    DBG("m_pEp=%p\n", m_pEd);
+    DBG("m_pTdHead->CurrBufPtr=%08x\n", (uint32_t)m_pTdHead->CurrBufPtr);
+    DBG("m_pBufStartPtr=%08x\n", (uint32_t) m_pBufStartPtr);
+    if(m_pTdHead->CurrBufPtr)
+      len = m_pTdHead->CurrBufPtr - (uint32_t) m_pBufStartPtr;
+    else
+      len = m_len;
+    /*if(len == 0) //Packet transfered completely
+      len = m_len;*/
+    //m_done = true;
+    DBG("Transfered %d bytes\n", len);
+    m_status = len; 
+  }
+  else
+  {
+    DBG("Unknown error...\n");
+    m_status = (int)USBERR_ERROR;
+  }
+  m_result = true;
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)();
+}
+
+
+ 
+void UsbEndpoint::sOnCompletion(uint32_t pTd)
+{
+    HCTD* td = td_reverse((HCTD*)pTd);
+    while(td) {
+        HCTD* next = (HCTD*)td->Next;
+        HCUTD* utd = (HCUTD*)td;
+        UsbEndpoint* pEp = (UsbEndpoint*)utd->UsbEndpoint;
+        DBG_ASSERT(pEp);
+        if (usb_is_itd((byte*)td)) {
+            HCITD* itd = (HCITD*)td;
+            DBG_ASSERT(pEp->m_type == USB_ISO);
+            pEp->queue_done_itd.push(itd);
+        } else {
+            DBG_ASSERT(pEp->m_pTdHead == td);
+            if(pEp->m_pTdHead == td) { // found?
+                pEp->onCompletion();
+            }
+        }
+        td = next;
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbEndpoint.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,100 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_ENDPOINT_H
+#define USB_ENDPOINT_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+#include "Usb_td.h"
+
+class UsbDevice;
+
+enum UsbEndpointType
+{
+  USB_CONTROL,
+  USB_BULK,
+  USB_INT,
+  USB_ISO
+};
+
+class UsbEndpoint
+{
+public:
+  UsbEndpoint( UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr = -1 );
+  ~UsbEndpoint();
+  void UsbEndpoint_iso(UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr);
+
+  void setNextToken(uint32_t token); //Only for control Eps
+  
+  UsbErr transfer(volatile uint8_t* buf, uint32_t len); 
+  UsbErr transfer(uint16_t frame, int count, volatile uint8_t* buf, int len); // for isochronous
+  int m_itdActive; 
+  tdqueue <HCITD*> queue_done_itd;
+  int status(); //return UsbErr or transfered len
+  
+  void updateAddr(int addr);
+  void updateSize(uint16_t size);
+  
+  //void setOnCompletion( void(*pCb)completed() );
+  class CDummy;
+  template <class T>
+  void setOnCompletion( T* pCbItem, void (T::*pCbMeth)() )
+  {
+    m_pCbItem = (CDummy*) pCbItem;
+    m_pCbMeth = (void (CDummy::*)()) pCbMeth;
+  }
+   
+//static void completed(){}
+
+protected:
+  void onCompletion();
+public:
+  static void sOnCompletion(uint32_t pTd);
+  
+private:
+  friend class UsbDevice;
+
+  UsbDevice* m_pDevice;
+  
+  bool m_dir;
+  bool m_setup;
+  UsbEndpointType m_type;
+  
+  //bool m_done;
+  volatile bool m_result;
+  volatile int m_status;
+  
+  volatile uint32_t m_len;
+  
+  volatile uint8_t* m_pBufStartPtr;
+
+  volatile HCED* m_pEd; //Ep descriptor
+
+  volatile HCTD* m_pTdHead; //Head trf descriptor
+  volatile HCTD* m_pTdTail; //Tail trf descriptor
+
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)();
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbEndpoint2.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,132 @@
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include "UsbEndpoint.h"
+#include "UsbDevice.h"
+#include "usb_mem.h"
+
+//#define __DEBUG
+//#define __DEBUG3
+//#include "dbg/dbg.h"
+#include "mydbg.h"
+
+void UsbEndpoint::UsbEndpoint_iso(UsbDevice* pDevice, uint8_t ep, bool dir, UsbEndpointType type, uint16_t size, int addr)
+{
+  m_itdActive = 0;
+  m_pEd = (volatile HCED*)usb_get_ed();
+  DBG_ASSERT(m_pEd);
+  memset((void*)m_pEd, 0, sizeof(HCED));
+  
+  m_pTdHead = NULL;
+  m_pTdTail = NULL;
+  
+  volatile HCTD* itd = (volatile HCTD*)usb_get_itd((uint32_t)this);
+  DBG_ASSERT(itd);
+  memset((void*)itd, 0, sizeof(HCITD));
+  DBG3("m_pEd =%p\n", m_pEd);
+  DBG3("itd   =%p\n", itd);
+  
+  if(addr == -1)
+    addr = pDevice->m_addr;
+  
+  //Setup Ed
+  //printf("\r\n--Ep Setup--\r\n");
+  m_pEd->Control =  addr | /* USB address */
+      ((ep & 0x7F) << 7) | /* Endpoint address */
+      ((dir?2:1) << 11)  | /* direction : Out = 1, 2 = In */
+      (1 << 15)          | /* F Format */
+      (size << 16);        /* MaxPkt Size */
+
+  DBG3("m_pEd->Control=%08X\n", m_pEd->Control);
+
+  m_dir = dir;
+  m_setup = false;
+  m_type = type;
+  
+  m_pEd->TailTd = m_pEd->HeadTd = (uint32_t)itd; //Empty TD list
+  
+  DBG("Before link\n");
+  
+  //printf("\r\n--Ep Reg--\r\n");
+  //Append Ed to Ed list
+  HCCA* hcca = (HCCA*)usb_get_hcca();
+  for(int i = 0; i < 32; i++) {
+    if (hcca->IntTable[i] == 0) {
+      hcca->IntTable[i] = (uint32_t)m_pEd;
+    } else {
+      volatile HCED* nextEd = (volatile HCED*)hcca->IntTable[i];
+      while(nextEd->Next && nextEd->Next != (uint32_t)m_pEd) {
+        nextEd = (volatile HCED*)nextEd->Next;
+      }
+      nextEd->Next = (uint32_t)m_pEd;
+    }
+  }
+}
+
+// for isochronous 
+UsbErr UsbEndpoint::transfer(uint16_t frame, int count, volatile uint8_t* buf, int len)
+{
+  DBG_ASSERT(count >= 1 && count <= 8);
+  DBG_ASSERT(buf);
+  DBG_ASSERT((len % count) == 0);
+  HCITD *itd = (HCITD*)m_pEd->TailTd;
+  DBG_ASSERT(itd); 
+  HCITD *new_itd = (HCITD*)usb_get_itd((uint32_t)this);
+  DBG_ASSERT(new_itd);
+  if (itd == NULL) {
+    return USBERR_ERROR;
+  }
+  DBG("itd=%p\n", itd);
+  DBG2("new_itd=%p\n", new_itd);
+  int di = 0; //DelayInterrupt
+  itd->Control = 0xe0000000        | // CC ConditionCode NOT ACCESSED
+                 ((count-1) << 24) | // FC FrameCount
+                 TD_DELAY_INT(di)  | // DI DelayInterrupt
+                 frame;              // SF StartingFrame
+  itd->BufferPage0 = (uint32_t)buf;
+  itd->BufferEnd = (uint32_t)buf+len-1;
+  itd->Next = (uint32_t)new_itd; 
+  uint16_t offset[8];
+  for(int i = 0; i < 8; i++) {
+      uint32_t addr = (uint32_t)buf + i*(len/count);
+      offset[i] = addr & 0x0fff;
+      if ((addr&0xfffff000) == (itd->BufferEnd&0xfffff000)) {
+          offset[i] |= 0x1000;
+      }
+      offset[i] |= 0xe000;
+  }
+  itd->OffsetPSW10 = (offset[1]<<16) | offset[0];
+  itd->OffsetPSW32 = (offset[3]<<16) | offset[2];
+  itd->OffsetPSW54 = (offset[5]<<16) | offset[4];
+  itd->OffsetPSW76 = (offset[7]<<16) | offset[6];
+  m_itdActive++;
+  DBG2("itd->Control    =%08X\n", itd->Control); 
+  DBG2("itd->BufferPage0=%08X\n", itd->BufferPage0); 
+  DBG2("itd->Next       =%08X\n", itd->Next); 
+  DBG2("itd->BufferEnd  =%08X\n", itd->BufferEnd); 
+  DBG2("itd->OffsetPSW10=%08X\n", itd->OffsetPSW10); 
+  DBG2("itd->OffsetPSW32=%08X\n", itd->OffsetPSW32); 
+  DBG2("itd->OffsetPSW54=%08X\n", itd->OffsetPSW54); 
+  DBG2("itd->OffsetPSW76=%08X\n", itd->OffsetPSW76); 
+  m_pEd->TailTd = (uint32_t)new_itd; // start!!!
+  LPC_USB->HcControl |= OR_CONTROL_PLE; //Enable Periodic
+  return USBERR_PROCESSING;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbHostMgr.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,395 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include "UsbHostMgr.h"
+#include "usb_mem.h"
+#include "Usb_td.h"
+#include "string.h" //For memcpy, memmove, memset
+#include "netCfg.h"
+#if NET_USB
+//#define __DEBUG
+//#define __DEBUG3
+//#include "dbg/dbg.h"
+#include "mydbg.h"
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+static UsbHostMgr* pMgr = NULL;
+
+extern "C" void sUsbIrqhandler(void) __irq
+{
+  DBG("\n+Int\n");
+  if(pMgr)
+    pMgr->UsbIrqhandler();
+  DBG("\n-Int\n");
+  return;
+}
+
+UsbHostMgr::UsbHostMgr() : m_lpDevices()
+{
+  /*if(!pMgr)*/ //Assume singleton
+  pMgr = this;
+  usb_mem_init();
+  for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
+      m_lpDevices[i] = NULL;
+  }
+  m_pHcca = (HCCA*) usb_get_hcca();
+  memset((void*)m_pHcca, 0, 0x100);
+  m_hardware_init = false;
+  DBG("Host manager at %p\n", this);
+  
+  test_td(); // TD test program
+}
+
+UsbHostMgr::~UsbHostMgr()
+{
+  if(pMgr == this)
+    pMgr = NULL;
+}
+
+UsbErr UsbHostMgr::init() //Initialize host
+{
+  DBG("m_hardware_init=%d\n", m_hardware_init);
+  if(m_hardware_init) {
+      return USBERR_OK;
+  }
+
+  NVIC_DisableIRQ(USB_IRQn);                           /* Disable the USB interrupt source           */
+  
+  LPC_SC->PCONP       &= ~(1UL<<31); //Cut power
+  wait(1);
+  
+  
+  // turn on power for USB
+  LPC_SC->PCONP       |= (1UL<<31);
+  // Enable USB host clock, port selection and AHB clock
+  LPC_USB->USBClkCtrl |= CLOCK_MASK;
+  // Wait for clocks to become available
+  while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
+      ;
+  
+  // it seems the bits[0:1] mean the following
+  // 0: U1=device, U2=host
+  // 1: U1=host, U2=host
+  // 2: reserved
+  // 3: U1=host, U2=device
+  // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+  // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+  LPC_USB->OTGStCtrl |= 1;
+  
+  // now that we've configured the ports, we can turn off the portsel clock
+  LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+  
+  // power pins are not connected on mbed, so we can skip them
+  /* P1[18] = USB_UP_LED, 01 */
+  /* P1[19] = /USB_PPWR,     10 */
+  /* P1[22] = USB_PWRD, 10 */
+  /* P1[27] = /USB_OVRCR, 10 */
+  /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22));  
+  LPC_PINCON->PINSEL3 |=  ((1<<4)|(2<<6) | (2<<12) | (2<<22));   // 0x00802080
+  */
+
+  // configure USB D+/D- pins
+  /* P0[29] = USB_D+, 01 */
+  /* P0[30] = USB_D-, 01 */
+  LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
+  LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
+      
+  DBG("Initializing Host Stack\n");
+  
+  wait_ms(100);                                   /* Wait 50 ms before apply reset              */
+  LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
+  LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
+  LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
+  
+                                                      /* SOFTWARE RESET                             */
+  LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+  LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
+  LPC_USB->HcPeriodicStart = FI*90/100;
+
+                                                      /* Put HC in operational state                */
+  LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+  LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power                           */
+  
+  LPC_USB->HcHCCA = (uint32_t)(m_pHcca);
+  LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;                   /* Clear Interrrupt Status                    */
+
+
+  LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE |
+                       OR_INTR_ENABLE_WDH |
+                       OR_INTR_ENABLE_RHSC;
+
+  NVIC_SetPriority(USB_IRQn, 0);       /* highest priority */
+  /* Enable the USB Interrupt */
+  NVIC_SetVector(USB_IRQn, (uint32_t)(sUsbIrqhandler));
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+  LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+  
+  
+  /* Check for any connected devices */
+  //if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+  //{
+  //  //Device connected
+  //  wait(1);
+  //  DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+  //  onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+  //}
+    
+  DBG("Enabling IRQ\n");
+  NVIC_EnableIRQ(USB_IRQn);
+  DBG("End of host stack initialization\n");
+  m_hardware_init = true;
+  return USBERR_OK;
+}
+
+UsbErr UsbHostMgr::poll() //Enumerate connected devices, etc
+{
+  /* Check for any connected devices */
+  if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+  {
+    //Device connected
+    wait(1);
+    DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+    onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+  }
+  
+  for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
+  {
+    UsbDevice* dev = m_lpDevices[i];
+    if (dev == NULL) {
+      continue;
+    }
+    DBG3("%d dev=%p %d %d addr=%d\n", i, dev, dev->m_connected, dev->m_enumerated, dev->m_addr);
+    if(dev->m_connected) {
+      if (!dev->m_enumerated) {
+          dev->enumerate();
+          return USBERR_PROCESSING;
+      }
+    }
+  }
+  for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
+    UsbDevice* dev = m_lpDevices[i];
+    if (dev == NULL) {
+      continue;
+    }   
+    if (dev->m_connected && dev->m_enumerated) {
+      if (dev->m_DeviceClass == 0x09) { // HUB
+        UsbErr rc = dev->hub_poll();
+        if (rc == USBERR_PROCESSING) {
+          return USBERR_PROCESSING;
+        } 
+      }
+    }
+  }
+  return USBERR_OK;
+}
+
+int UsbHostMgr::devicesCount()
+{
+  int i;
+  for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
+  {
+    if (m_lpDevices[i] == NULL) {
+      return i;
+    }
+  }
+  return i;
+}
+
+UsbDevice* UsbHostMgr::getDevice(int item)
+{
+  UsbDevice* pDev = m_lpDevices[item];
+  if(!pDev)
+    return NULL;
+    
+  pDev->m_refs++;
+  return pDev;
+}
+
+void UsbHostMgr::releaseDevice(UsbDevice* pDev)
+{
+  DBG_ASSERT(0);
+
+  pDev->m_refs--;
+  if(pDev->m_refs > 0)
+    return;
+  //If refs count = 0, delete
+  //Find & remove from list
+  int i;
+  for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
+  {
+    if (m_lpDevices[i] == pDev)
+      break;
+  }
+  if(i!=USB_HOSTMGR_MAX_DEVS)
+    memmove(&m_lpDevices[i], &m_lpDevices[i+1], sizeof(UsbDevice*) * (USB_HOSTMGR_MAX_DEVS - (i + 1))); //Safer than memcpy because of overlapping mem
+  m_lpDevices[USB_HOSTMGR_MAX_DEVS - 1] = NULL;
+  delete pDev;
+}
+
+void UsbHostMgr::UsbIrqhandler()
+{
+  uint32_t   int_status;
+  uint32_t   ie_status;
+  
+  int_status    = LPC_USB->HcInterruptStatus;                          /* Read Interrupt Status                */
+  ie_status     = LPC_USB->HcInterruptEnable;                          /* Read Interrupt enable status         */
+
+  if (!(int_status & ie_status))
+  {
+    return;
+  }
+  else
+  {
+    int_status = int_status & ie_status;
+    if (int_status & OR_INTR_STATUS_RHSC) /* Root hub status change interrupt     */
+    {
+      DBG("LPC_USB->HcRhPortStatus1 = %08x\n", LPC_USB->HcRhPortStatus1);
+      if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC)
+      {
+        if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE)
+        {
+            /*
+             * When DRWE is on, Connect Status Change
+             * means a remote wakeup event.
+            */
+            //HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT
+        }
+        else
+        {
+          /*
+           * When DRWE is off, Connect Status Change
+           * is NOT a remote wakeup event
+          */
+          if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
+          {
+            //Device connected
+            DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
+            onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
+          }
+          else //Root device disconnected
+          {
+            //Device disconnected
+            DBG("Device disconnected\n");
+            onUsbDeviceDisconnected(0, 1);
+          }
+          //TODO: HUBS
+        }
+        LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+      }
+      if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC)
+      {
+        LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+      }
+    }  
+    if (int_status & OR_INTR_STATUS_WDH) /* Writeback Done Head interrupt        */
+    {                  
+      //UsbEndpoint::sOnCompletion((LPC_USB->HccaDoneHead) & 0xFE);
+      if(m_pHcca->DoneHead)
+      {
+        UsbEndpoint::sOnCompletion(m_pHcca->DoneHead);
+        m_pHcca->DoneHead = 0;
+        LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+        if(m_pHcca->DoneHead)
+          DBG("??????????????????????????????\n\n\n");
+      }
+      else
+      {
+        //Probably an error
+        int_status = LPC_USB->HcInterruptStatus;
+        DBG("HcInterruptStatus = %08x\n", int_status);
+        if (int_status & OR_INTR_STATUS_UE) //Unrecoverable error, disconnect devices and resume
+        {
+          onUsbDeviceDisconnected(0, 1);
+          LPC_USB->HcInterruptStatus = OR_INTR_STATUS_UE;
+          LPC_USB->HcCommandStatus = 0x01; //Host Controller Reset
+        }
+      }
+    }
+    LPC_USB->HcInterruptStatus = int_status; /* Clear interrupt status register      */
+  }
+  return;
+}
+
+void UsbHostMgr::onUsbDeviceDisconnected(int hub, int port)
+{
+  for(int i = 0; i < devicesCount(); i++)
+  {
+     if( (m_lpDevices[i]->m_hub == hub)
+     &&  (m_lpDevices[i]->m_port == port) )
+     {
+       m_lpDevices[i]->m_connected = false;
+       if(!m_lpDevices[i]->m_enumerated)
+       {
+         delete m_lpDevices[i];
+         m_lpDevices[i] = NULL;
+       }
+       return;
+     }
+  }
+}
+
+void UsbHostMgr::resetPort(int hub, int port)
+{
+  DBG3("hub=%d port=%d\n", hub, port);
+  if(hub == 0) //Root hub
+  {
+    wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+    DBG("Before loop\n");
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+      ;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+    DBG("After loop\n");
+    wait_ms(200); /* Wait for 100 MS after port reset  */
+  }
+  else
+  {
+    for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
+      UsbDevice* dev = m_lpDevices[i];
+      if (dev == NULL) {
+        continue;
+      }
+      if (dev->m_addr == hub) {
+        DBG("%d dev=%p\n", i, dev);
+        dev->hub_PortReset(port);
+        return;
+      }
+    }
+    DBG_ASSERT(0);
+  }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbHostMgr.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+//Assigns addresses to connected devices...
+
+#ifndef USB_HOSTMGR_H
+#define USB_HOSTMGR_H
+
+#include "mbed.h"
+#include "UsbInc.h"
+#include "UsbDevice.h"
+
+#define USB_HOSTMGR_MAX_DEVS 8
+
+class UsbDevice;
+
+class UsbHostMgr //[0-2] inst
+{
+public:
+  UsbHostMgr();
+  ~UsbHostMgr();
+  
+  UsbErr init(); //Initialize host
+  
+  UsbErr poll(); //Enumerate connected devices, etc
+  
+  int devicesCount();
+  
+  UsbDevice* getDevice(int item);
+  UsbDevice* getDeviceByClass(uint8_t IfClass, int count = 0);
+  void releaseDevice(UsbDevice* pDev);
+  
+
+  void UsbIrqhandler();
+
+protected:  
+  void onUsbDeviceConnected(int hub, int port);
+  void onUsbDeviceDisconnected(int hub, int port);
+  
+  friend class UsbDevice;
+  void resetPort(int hub, int port);
+  
+private:
+/*  __align(8)*/ volatile HCCA* m_pHcca;
+  
+  UsbDevice* m_lpDevices[USB_HOSTMGR_MAX_DEVS];
+  bool m_hardware_init; 
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbHostMgr2.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,51 @@
+#include "UsbHostMgr.h"
+//#define __DEBUG
+#include "mydbg.h"
+
+UsbDevice* UsbHostMgr::getDeviceByClass(uint8_t IfClass, int count)
+{
+    DBG("IfClass=%02X count=%d\n", IfClass, count);
+    for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
+       UsbDevice* dev = m_lpDevices[i];
+       if (dev) {
+           if(dev->m_connected && dev->m_enumerated) {
+               if (dev->m_InterfaceClass == IfClass) { // found
+                   if (count-- <= 0) {
+                       return dev;
+                   }
+               }
+           }
+       }
+    }
+    return NULL;
+}
+
+void UsbHostMgr::onUsbDeviceConnected(int hub, int port)
+{
+  DBG("%p hub=%d port=%d\n", this, hub, port);
+  for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
+      UsbDevice* dev = m_lpDevices[i];
+      if (dev) {
+          if (dev->m_hub == hub && dev->m_port == port) { // skip
+              return;
+          }
+      }
+  }
+  
+  int item = devicesCount();
+  DBG_ASSERT(item < USB_HOSTMGR_MAX_DEVS);
+  if( item == USB_HOSTMGR_MAX_DEVS )
+    return; //List full...
+  //Find a free address (not optimized, but not really important)
+  int addr = 1;
+  for(int i = 0; i < item; i++)
+  {
+    DBG_ASSERT(m_lpDevices[i]);
+    addr = MAX( addr, m_lpDevices[i]->m_addr + 1 );
+  }
+  DBG("item=%d addr=%d\n", item, addr);
+  UsbDevice* dev = new UsbDevice( this, hub, port, addr );
+  DBG_ASSERT(dev);
+  dev->m_connected = true;
+  m_lpDevices[item] = dev;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbInc.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,227 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+//typedef int32_t RC;
+
+typedef uint8_t byte;
+typedef uint16_t word;
+
+enum UsbErr
+{
+  __USBERR_MIN = -0xFFFF,
+  USBERR_DISCONNECTED,
+  USBERR_NOTFOUND,
+  USBERR_BADCONFIG,
+  USBERR_PROCESSING,
+  USBERR_HALTED, //Transfer on an ep is stalled
+  USBERR_BUSY,
+  USBERR_TDFAIL,
+  USBERR_ERROR,
+  USBERR_OK = 0
+};
+
+
+/* From NXP's USBHostLite stack's usbhost_lpc17xx.h */
+/* Only the types names have been changed to avoid unecessary typedefs */
+
+
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_lpc17xx.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+
+
+/*
+**************************************************************************************************************
+*                                  OHCI OPERATIONAL REGISTER FIELD DEFINITIONS
+**************************************************************************************************************
+*/
+
+                                            /* ------------------ HcControl Register ---------------------  */
+#define  OR_CONTROL_PLE                 0x00000004
+#define  OR_CONTROL_IE                  0x00000008
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+                                            /* ----------------- HcCommandStatus Register ----------------- */
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+                                            /* --------------- HcInterruptStatus Register ----------------- */
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_RHSC            0x00000040
+#define  OR_INTR_STATUS_UE              0x00000010
+                                            /* --------------- HcInterruptEnable Register ----------------- */
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+                                            /* ---------------- HcRhDescriptorA Register ------------------ */
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+                                            /* -------------- HcRhPortStatus[1:NDP] Register -------------- */
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+
+
+/*
+**************************************************************************************************************
+*                                               FRAME INTERVAL
+**************************************************************************************************************
+*/
+
+#define  FI                     0x2EDF           /* 12000 bits per frame (-1)                               */
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+/*
+**************************************************************************************************************
+*                                       ENDPOINT DESCRIPTOR CONTROL FIELDS
+**************************************************************************************************************
+*/
+
+#define  ED_SKIP            (uint32_t) (0x00001000)        /* Skip this ep in queue                       */
+
+/*
+**************************************************************************************************************
+*                                       TRANSFER DESCRIPTOR CONTROL FIELDS
+**************************************************************************************************************
+*/
+
+#define  TD_ROUNDING        (uint32_t) (0x00040000)        /* Buffer Rounding                             */
+#define  TD_SETUP           (uint32_t)(0)                  /* Direction of Setup Packet                   */
+#define  TD_IN              (uint32_t)(0x00100000)         /* Direction In                                */
+#define  TD_OUT             (uint32_t)(0x00080000)         /* Direction Out                               */
+#define  TD_DELAY_INT(x)    (uint32_t)((x) << 21)          /* Delay Interrupt                             */
+#define  TD_TOGGLE_0        (uint32_t)(0x02000000)         /* Toggle 0                                    */
+#define  TD_TOGGLE_1        (uint32_t)(0x03000000)         /* Toggle 1                                    */
+#define  TD_CC              (uint32_t)(0xF0000000)         /* Completion Code                             */
+
+#define  ITD_SF             (uint32_t)(0x0000FFFF)         /* Starting Frame */
+#define  ITD_FC             (uint32_t)(0x07000000)         /* FrameCount */
+
+/*
+**************************************************************************************************************
+*                                       USB STANDARD REQUEST DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  USB_DESCRIPTOR_TYPE_DEVICE                     1
+#define  USB_DESCRIPTOR_TYPE_CONFIGURATION              2
+#define  USB_DESCRIPTOR_TYPE_STRING                     3
+#define  USB_DESCRIPTOR_TYPE_INTERFACE                  4
+#define  USB_DESCRIPTOR_TYPE_ENDPOINT                   5
+#define  USB_DESCRIPTOR_TYPE_HUB                     0x29
+                                                    /*  ----------- Control RequestType Fields  ----------- */
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+#define  USB_RECIPIENT_OTHER        0x03
+
+                                                /* -------------- USB Standard Requests  -------------- */
+#define  GET_STATUS                  0
+#define  CLEAR_FEATURE               1
+#define  SET_FEATURE                 3
+#define  SET_ADDRESS                 5
+#define  GET_DESCRIPTOR              6
+#define  SET_CONFIGURATION           9
+#define  SET_INTERFACE              11
+
+/*
+**************************************************************************************************************
+*                                       TYPE DEFINITIONS
+**************************************************************************************************************
+*/
+
+typedef struct hcEd {                       /* ----------- HostController EndPoint Descriptor ------------- */
+    volatile  uint32_t  Control;              /* Endpoint descriptor control                              */
+    volatile  uint32_t  TailTd;               /* Physical address of tail in Transfer descriptor list     */
+    volatile  uint32_t  HeadTd;               /* Physcial address of head in Transfer descriptor list     */
+    volatile  uint32_t  Next;                 /* Physical address of next Endpoint descriptor             */
+} HCED;
+
+typedef struct hcTd {                       /* ------------ HostController Transfer Descriptor ------------ */
+    volatile  uint32_t  Control;              /* Transfer descriptor control                              */
+    volatile  uint32_t  CurrBufPtr;           /* Physical address of current buffer pointer               */
+    volatile  uint32_t  Next;                 /* Physical pointer to next Transfer Descriptor             */
+    volatile  uint32_t  BufEnd;               /* Physical address of end of buffer                        */
+} HCTD;
+
+typedef struct hcItd {               // HostController Isochronous Transfer Descriptor
+    volatile  uint32_t  Control;     // Transfer descriptor control
+    volatile  uint32_t  BufferPage0; // Buffer Page 0
+    volatile  uint32_t  Next;        // Physical pointer to next Transfer Descriptor
+    volatile  uint32_t  BufferEnd;   // buffer End
+    volatile  uint32_t  OffsetPSW10; // Offset1/PSW1 Offset0/PSW0
+    volatile  uint32_t  OffsetPSW32; // Offset3/PSW3 Offset2/PSW2
+    volatile  uint32_t  OffsetPSW54; // Offset5/PSW5 Offset4/PSW4
+    volatile  uint32_t  OffsetPSW76; // Offset7/PSW7 Offset6/PSW6
+} HCITD;
+
+typedef struct hcUtd {
+    union {
+        HCTD  hctd;
+        HCITD hcitd;
+    };
+    volatile uint32_t type;        // 1:TD, 2:ITD 
+    volatile uint32_t UsbEndpoint;
+    volatile uint32_t reserve1;
+    volatile uint32_t reserve2;
+} HCUTD;
+
+typedef struct hcca {                       /* ----------- Host Controller Communication Area ------------  */
+    volatile  uint32_t  IntTable[32];         /* Interrupt Table                                          */
+    volatile  uint32_t  FrameNumber;          /* Frame Number                                             */
+    volatile  uint32_t  DoneHead;             /* Done Head                                                */
+    volatile  uint8_t  Reserved[116];        /* Reserved for future use                                  */
+    volatile  uint8_t  Unknown[4];           /* Unused                                                   */
+} HCCA;
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/Usb_td.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,240 @@
+#include "mbed.h"
+#include "Usb_td.h"
+//#define __DEBUG
+#include "mydbg.h"
+
+#define __TEST
+
+#ifdef __TEST
+#include <queue>
+#endif
+
+template class tdqueue<HCTD*>;
+template class tdqueue<HCITD*>;
+
+HCTD* td_reverse(HCTD* td)
+{
+    HCTD* result = NULL;
+    HCTD* next;
+    while(td) {
+        next = (HCTD*)td->Next;
+        td->Next = (uint32_t)result;
+        result = td;
+        td = next;
+    }
+    return result;
+}
+
+template <class T>
+tdqueue<T>::tdqueue():m_head(NULL),m_tail(NULL)
+{
+
+}
+
+template <class T>
+int tdqueue<T>::size()
+{
+    int n = 0;
+    T td = m_head;
+    while(td) {
+        td = (T)td->Next;
+        n++;
+    }
+    return n;
+}
+
+template <class T>
+bool tdqueue<T>::empty()
+{
+    return (m_head == NULL);
+}
+
+template <class T>
+T tdqueue<T>::front()
+{
+    return m_head;
+}
+
+template <class T>
+void tdqueue<T>::pop()
+{
+    T td = m_head;
+    if (td) {
+        m_head = (T)td->Next;
+    }
+    if (td == m_tail) {
+        m_tail = NULL;
+    }
+}
+
+template <class T>
+void tdqueue<T>::push(T td)
+{
+    td->Next = NULL;
+    if (m_tail) {
+        m_tail->Next = (uint32_t)td;
+    }
+    m_tail = td;
+    if (m_head == NULL) {
+        m_head = td;
+    }
+}
+
+#ifdef __TEST
+static void test_td_list()
+{
+    tdqueue<HCTD*> list;
+    HCTD* td1;
+    HCTD* td2;
+    HCTD* td3;
+    HCTD* td4;
+    // 0
+    DBG_ASSERT(list.size() == 0);
+    td1 = list.front();
+    DBG_ASSERT(td1  == NULL);
+    list.pop();
+    td1 = list.front();
+    DBG_ASSERT(td1 == NULL);
+    // 1   
+    td1 = (HCTD*)usb_get_td(1);
+    list.push(td1);
+    DBG_ASSERT(list.size() == 1);
+    td2 = list.front();
+    DBG_ASSERT(td2 == td1);
+    list.pop();
+    td2 = list.front();
+    DBG_ASSERT(td2 == NULL);
+    DBG_ASSERT(list.size() == 0);
+    usb_free_td((byte*)td1);
+    // 2
+    td1 = (HCTD*)usb_get_td(1);
+    td2 = (HCTD*)usb_get_td(2);
+    list.push(td1);
+    list.push(td2);
+    DBG_ASSERT(list.size() == 2);
+    td3 = list.front();
+    DBG_ASSERT(td3 == td1);
+    list.pop();
+    td3 = list.front();
+    DBG_ASSERT(td3 == td2);
+    list.pop();
+    td3 = list.front();
+    DBG_ASSERT(td3 == NULL); 
+    usb_free_td((byte*)td1);
+    usb_free_td((byte*)td2);
+    // 3 
+    td1 = (HCTD*)usb_get_td(1);
+    td2 = (HCTD*)usb_get_td(2);
+    td3 = (HCTD*)usb_get_td(3);
+    list.push(td1);
+    list.push(td2);
+    list.push(td3);
+    DBG_ASSERT(list.size() == 3);
+    td4 = list.front();
+    DBG_ASSERT(td4 == td1);
+    list.pop();
+    td4 = list.front();
+    DBG_ASSERT(td4 == td2);
+    list.pop();
+    td4 = list.front();
+    DBG_ASSERT(td4 == td3);
+    list.pop();
+    td4 = list.front();
+    DBG_ASSERT(td4 == NULL);    
+    usb_free_td((byte*)td1);
+    usb_free_td((byte*)td2);
+    usb_free_td((byte*)td3);
+    // n
+    queue<HCTD*> queue;
+    for(int n = 1; n <= 10; n++) {
+        DBG_ASSERT(list.size() == queue.size());
+        DBG_ASSERT(list.empty() == queue.empty());
+        if (list.empty() || (rand()%10) > 5) {
+            td1 = (HCTD*)usb_get_td(n);
+            if (td1) {
+                list.push(td1);
+                queue.push(td1);
+            }
+            //DBG("+ %d %p\n", n, td1);
+        } else {
+            td1 = list.front();
+            td2 = queue.front();
+            if (td1 != td2) {
+                //DBG("td1=%p td2=%p\n", td1, td2);
+            }
+            DBG_ASSERT(td1 == td2);
+            if (td1) {
+                list.pop();
+                queue.pop();
+                usb_free_td((byte*)td1);
+            }
+            //DBG("- %d %p\n", n, td1);
+        }
+    }
+    while(!list.empty()) {
+        td1 = list.front();
+        list.pop();
+        usb_free_td((byte*)td1);
+    }
+    //DBG_ASSERT(0);    
+}
+
+static void test_td_reverse()
+{
+
+    HCTD* td1;
+    HCTD* td2;
+    HCTD* td3;
+    HCTD* td4;
+    // 0
+    td1 = NULL;
+    td2 = td_reverse(td1);
+    DBG_ASSERT(td2 == NULL);
+    // 1
+    td1 = (HCTD*)usb_get_td(1);
+    DBG_ASSERT(td1);
+    DBG_ASSERT(td1->Next == NULL);
+    td2 = td_reverse(td1);
+    DBG_ASSERT(td2 == td1);
+    DBG_ASSERT(td2->Next == NULL);
+    usb_free_td((byte*)td1);
+    // 2
+    td1 = (HCTD*)usb_get_td(1);
+    DBG_ASSERT(td1);
+    td2 = (HCTD*)usb_get_td(2);
+    DBG_ASSERT(td2);
+    td1->Next = (uint32_t)td2;
+    td3 = td_reverse(td1);
+    DBG_ASSERT(td3 == td2);
+    DBG_ASSERT(td3->Next == (uint32_t)td1);
+    DBG_ASSERT(td1->Next == NULL);
+    usb_free_td((byte*)td1);
+    usb_free_td((byte*)td2);
+    // 3
+    td1 = (HCTD*)usb_get_td(1);
+    td2 = (HCTD*)usb_get_td(2);
+    td3 = (HCTD*)usb_get_td(3);
+    td1->Next = (uint32_t)td2;
+    td2->Next = (uint32_t)td3;
+    td4 = td_reverse(td1);
+    DBG_ASSERT(td4 == td3);
+    DBG_ASSERT(td3->Next == (uint32_t)td2);
+    DBG_ASSERT(td2->Next == (uint32_t)td1);
+    DBG_ASSERT(td1->Next == NULL);
+    usb_free_td((byte*)td1);
+    usb_free_td((byte*)td2);
+    usb_free_td((byte*)td3);
+}
+
+void test_td()
+{
+    test_td_reverse();
+    test_td_list();
+    DBG("Usb_td.cpp TD test done.\n");
+}
+#else  //__TEST
+void test_td()
+{
+
+}
+#endif //__TEST
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/Usb_td.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,23 @@
+#ifndef USB_TD_H
+#define USB_TD_H
+#include "UsbInc.h"
+#include "usb_mem.h"
+
+template <class T> 
+class tdqueue {
+public:
+    tdqueue();
+    int size();
+    bool empty();
+    T front();
+    void pop();
+    void push(T td);
+private:
+    T m_head;
+    T m_tail;
+};
+
+HCTD* td_reverse(HCTD* td);
+void test_td();
+
+#endif //USB_TD_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/Utils.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,48 @@
+
+
+#include "mbed.h"
+#include "Utils.h"
+
+void printfBytes(const char* s, const u8* data, int len)
+{
+    printf("%s %d:",s,len);
+    if (len > 256)
+        len = 256;
+    while (len-- > 0)
+        printf(" %02X",*data++);
+    printf("\n");
+}
+
+void printHexLine(const u8* d, int addr, int len)
+{
+    printf("%04X ",addr);
+    int i;
+    for (i = 0; i < len; i++)
+        printf("%02X ",d[i]);
+    for (;i < 16; i++)
+        printf("   ");
+    char s[16+1];
+    memset(s,0,sizeof(s));
+    for (i = 0; i < len; i++)
+    {
+        int c = d[i];
+        if (c < 0x20 || c > 0x7E)
+            c = '.';
+        s[i] = c;
+    }
+    printf("%s\n",s);
+}
+
+void printHex(const u8* d, int len)
+{
+    int addr = 0;
+    while (len)
+    {
+        int count = len;
+        if (count > 16)
+            count = 16;
+        printHexLine(d+addr,addr,count);
+        addr += 16;
+        len -= count;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/Utils.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,48 @@
+#ifndef UTILS_H
+#define UTILS_H
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+//void DelayMS(int ms);
+
+void printfBytes(const char* label,const u8* data, int len);
+void printHex(const u8* d, int len);
+
+#ifndef min
+#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+inline int LE16(const u8* d)
+{
+    return d[0] | (d[1] << 8);
+}
+
+
+inline int LE24(const uint8_t* d) {
+    return d[0] | (d[1]<<8) | (d[2] << 16);
+}
+
+inline int LE32(const uint8_t* d) {
+    return d[0] |(d[1]<<8) | (d[2] << 16) |(d[3] << 24) ;
+}
+
+inline u32 BE32(const u8* d)
+{
+    return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+inline void BE32(u32 n, u8* d)
+{
+    d[0] = (u8)(n >> 24);
+    d[1] = (u8)(n >> 16);
+    d[2] = (u8)(n >> 8);
+    d[3] = (u8)n;
+}
+
+inline void BE16(u32 n, u8* d)
+{
+    d[0] = (u8)(n >> 8);
+    d[1] = (u8)n;
+}
+#endif //UTILS_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/mydbg.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,35 @@
+#ifndef _MYDBG_H_
+#define _MYDBG_H_
+
+#ifdef __DEBUG
+#include "Utils.h"
+#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
+#define DBG2(...) do{fprintf(stderr,"[%d] ",__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
+#define DBG_BYTES(A,B,C) do{printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);printfBytes(A,B,C);}while(0);
+#define DBG_HEX(A,B) do{printf("[%s@%d]\n",__PRETTY_FUNCTION__,__LINE__);printHex(A,B);}while(0);
+#define DBG_LED4(A) led4.write(A)
+#define DBG_PRINTF(...) do{fprintf(stderr,__VA_ARGS__);} while(0);
+#else //__DEBUG
+#define DBG(...)  while(0);
+#define DBG2(...)  while(0);
+#define DBG_BYTES(A,B,C) while(0);
+#define DBG_HEX(A,B)  while(0);
+#define DBG_LED4(A) while(0);
+#define DBG_PRINTF(...)  while(0);
+#endif //__DEBUG
+
+#ifdef __DEBUG3
+#define DBG3(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
+#else //__DEBUG3
+#define DBG3(...)  while(0);
+#endif //__DEBUG3
+
+#ifndef __NODEBUG
+#define DBG_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#else
+#define DBG_ASSERT(A)  while(0);
+#endif
+
+#define VERBOSE(...) do{printf(__VA_ARGS__);} while(0);
+
+#endif //_MYDBG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/netCfg.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,11 @@
+#ifndef NET_CFG_H
+#define NET_GPRS 1
+#define NET_PPP 1
+#define NET_GPRS_MODULE 1
+#define NET_ETH 1
+#define NET_USB_SERIAL 1
+#define NET_CFG_H 1
+#define NET_UMTS 1
+#define NET_USB 1
+#define NET_LWIP_STACK 1
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/usb_mem.c	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,260 @@
+
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include "mbed.h"
+//#define __DEBUG
+#include "mydbg.h"
+#include "usb_mem.h"
+#include "string.h" //For memcpy, memmove, memset
+//#include "netCfg.h"
+#include "UsbInc.h"
+
+//#if NET_USB
+
+#define EDS_COUNT 16
+#define TDS_COUNT  0
+#define ITDS_COUNT 0
+#define UTDS_COUNT 32
+#define BPS_COUNT 8
+
+#define HCCA_SIZE 0x100
+#define ED_SIZE 0x10
+#define TD_SIZE 0x10
+#define ITD_SIZE 0x20
+#define UTD_SIZE (32+16)
+#define BP_SIZE  (128*8)
+
+#define TOTAL_SIZE (HCCA_SIZE + (EDS_COUNT*ED_SIZE) + (TDS_COUNT*TD_SIZE) + (ITDS_COUNT*ITD_SIZE))
+
+static volatile __align(256) byte usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM0"),aligned));  //256 bytes aligned!
+static volatile __align(32) uint8_t usb_utdBuf[UTDS_COUNT*UTD_SIZE] __attribute((section("AHBSRAM0"),aligned));
+
+static volatile byte* usb_hcca;  //256 bytes aligned!
+
+static volatile byte* usb_edBuf;  //4 bytes aligned!
+
+static byte usb_edBufAlloc[EDS_COUNT] __attribute((section("AHBSRAM0"),aligned));
+static uint8_t usb_utdBufAlloc[UTDS_COUNT] __attribute((section("AHBSRAM0"),aligned));
+static uint8_t usb_bpBufAlloc[BPS_COUNT] __attribute((section("AHBSRAM0"),aligned));
+static uint8_t usb_bpBuf[BP_SIZE*BPS_COUNT] __attribute((section("AHBSRAM0"),aligned));
+
+static void utd_init()
+{
+    DBG_ASSERT(sizeof(HCTD) == 16);
+    DBG_ASSERT(sizeof(HCITD) == 32);
+    DBG_ASSERT(sizeof(HCUTD) == 48);
+
+    DBG_ASSERT(((uint32_t)usb_utdBuf % 16) == 0);
+    DBG_ASSERT(((uint32_t)usb_utdBuf % 32) == 0);
+
+    DBG_ASSERT((uint32_t)usb_utdBufAlloc >= 0x2007c000);
+    DBG_ASSERT((uint32_t)&usb_utdBufAlloc[UTDS_COUNT] <= 0x2007ffff);
+
+    DBG_ASSERT((uint32_t)usb_utdBuf >= 0x2007c000);
+    DBG_ASSERT((uint32_t)&usb_utdBuf[UTD_SIZE*UTDS_COUNT] <= 0x2007cfff);
+
+    memset(usb_utdBufAlloc, 0x00, UTDS_COUNT);
+}
+
+static void pb_init()
+{
+    memset(usb_bpBufAlloc, 0x00, BPS_COUNT);
+
+    DBG_ASSERT((uint32_t)usb_bpBufAlloc >= 0x2007c000);
+    DBG_ASSERT((uint32_t)&usb_bpBufAlloc[BPS_COUNT] <= 0x2007ffff);
+    DBG_ASSERT((uint32_t)usb_bpBuf >= 0x2007c000);
+    DBG_ASSERT((uint32_t)(&usb_bpBuf[BP_SIZE*BPS_COUNT]) <= 0x2007ffff);
+}
+
+void usb_mem_init()
+{
+  usb_hcca = usb_buf;
+  usb_edBuf = usb_buf + HCCA_SIZE;
+  memset(usb_edBufAlloc, 0, EDS_COUNT);
+
+  utd_init();
+  pb_init();
+
+  DBG("--- Memory Map --- \n");
+  DBG("usb_hcca       =%p\n", usb_hcca);
+  DBG("usb_edBuf      =%p\n", usb_edBuf);
+  DBG("usb_utdBuf     =%p\n", usb_utdBuf);
+  DBG("usb_edBufAlloc =%p\n", usb_edBufAlloc);
+  DBG("usb_utdBufAlloc=%p\n", usb_utdBufAlloc);
+  DBG("usb_bpBufAlloc =%p\n", usb_bpBufAlloc);
+  DBG("usb_bpBuf      =%p\n", usb_bpBuf);
+  DBG("               =%p\n", &usb_bpBuf[BP_SIZE*BPS_COUNT]);
+  DBG_ASSERT(((uint32_t)usb_hcca % 256) == 0);
+  DBG_ASSERT(((uint32_t)usb_edBuf % 16) == 0);
+  DBG_ASSERT(((uint32_t)usb_utdBuf % 32) == 0);
+}
+
+volatile byte* usb_get_hcca()
+{
+  return usb_hcca;
+}
+
+volatile byte* usb_get_ed()
+{
+  int i;
+  for(i = 0; i < EDS_COUNT; i++)
+  {
+    if( !usb_edBufAlloc[i] )
+    {
+      usb_edBufAlloc[i] = 1;
+      return usb_edBuf + i*ED_SIZE;
+    }
+  }
+  return NULL; //Could not alloc ED
+}
+
+static uint8_t* usb_get_utd(int al)
+{
+    DBG_ASSERT(al == 16 || al == 32); // GTD or ITD
+    if (al == 16) {
+        for(int i = 1; i < UTDS_COUNT; i += 2) {
+            if (usb_utdBufAlloc[i] == 0) {
+                uint32_t p = (uint32_t)usb_utdBuf + i * UTD_SIZE;
+                if ((p % al) == 0) {
+                    usb_utdBufAlloc[i] = 1;
+                    DBG_ASSERT((p % al) == 0);
+                    return (uint8_t*)p;
+                }
+            }
+        }
+    }
+    for(int i = 0; i < UTDS_COUNT; i++) {
+        if (usb_utdBufAlloc[i] == 0) {
+            uint32_t p = (uint32_t)usb_utdBuf + i * UTD_SIZE;
+            if ((p % al) == 0) {
+                usb_utdBufAlloc[i] = 1;
+                DBG_ASSERT((p % al) == 0);
+                return (uint8_t*)p;
+            }
+        }
+    }
+    return NULL;
+}
+
+volatile byte* usb_get_td(uint32_t endpoint)
+{
+    DBG_ASSERT(endpoint);
+    uint8_t* td = usb_get_utd(16);
+    if (td) {
+        HCUTD* utd = (HCUTD*)td;
+        memset(utd, 0x00, sizeof(HCTD));
+        utd->type = 1;
+        utd->UsbEndpoint = endpoint;
+    }
+    return td;
+}
+
+volatile byte* usb_get_itd(uint32_t endpoint)
+{
+    DBG_ASSERT(endpoint);
+    uint8_t* itd = usb_get_utd(32);
+    if (itd) {
+        HCUTD* utd = (HCUTD*)itd;
+        memset(utd, 0x00, sizeof(HCITD));
+        utd->type = 2;
+        utd->UsbEndpoint = endpoint;
+    }
+    return itd;
+}
+
+volatile byte* usb_get_bp(int size)
+{
+  DBG_ASSERT(size >= 128 && size <= BP_SIZE);
+  if (size > BP_SIZE) {
+      return NULL;
+  }    
+  for(int i = 0; i < BPS_COUNT; i++)
+  {
+    if( !usb_bpBufAlloc[i] )
+    {
+      usb_bpBufAlloc[i] = 1;
+      return usb_bpBuf + i*BP_SIZE;
+    }
+  }
+  return NULL; //Could not alloc Buffer Page
+}
+
+int usb_bp_size()
+{
+    return BP_SIZE; 
+}
+
+void usb_free_ed(volatile byte* ed)
+{
+  int i;
+  i = (ed - usb_edBuf) / ED_SIZE;
+  usb_edBufAlloc[i] = 0;
+}
+
+static void usb_free_utd(volatile uint8_t* utd)
+{
+  DBG_ASSERT(utd >= usb_utdBuf);
+  DBG_ASSERT(utd <= (usb_utdBuf+UTD_SIZE*(UTDS_COUNT-1)));
+  DBG_ASSERT(((uint32_t)utd % 16) == 0);
+  int i = (utd - usb_utdBuf) / UTD_SIZE;
+  DBG_ASSERT(usb_utdBufAlloc[i] == 1);
+  usb_utdBufAlloc[i] = 0;
+}
+
+void usb_free_td(volatile byte* td)
+{
+    usb_free_utd(td);
+    return;
+}
+
+void usb_free_itd(volatile byte* itd)
+{
+    usb_free_utd(itd);
+    return;
+}
+
+void usb_free_bp(volatile byte* bp)
+{
+  DBG_ASSERT(bp >= usb_bpBuf);
+  int i;
+  i = (bp - usb_bpBuf) / BP_SIZE;
+  DBG_ASSERT(usb_bpBufAlloc[i] == 1);
+  usb_bpBufAlloc[i] = 0;
+}
+
+bool usb_is_td(volatile byte* td)
+{
+    DBG_ASSERT(td);
+    HCUTD* utd = (HCUTD*)td;
+    DBG_ASSERT(utd->type != 0);
+    return utd->type == 1;
+}
+
+bool usb_is_itd(volatile byte* itd)
+{
+    DBG_ASSERT(itd);
+    HCUTD* utd = (HCUTD*)itd;
+    DBG_ASSERT(utd->type != 0);
+    return utd->type == 2;
+}
+
+//#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/usb_mem.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef USB_MEM_H
+#define USB_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char byte;
+
+void usb_mem_init();
+
+volatile byte* usb_get_hcca();
+
+volatile byte* usb_get_ed();
+
+volatile byte* usb_get_td(uint32_t endpoint);
+volatile byte* usb_get_itd(uint32_t endpoint);
+
+volatile byte* usb_get_bp(int size);
+int usb_bp_size();
+
+void usb_free_ed(volatile byte* ed);
+
+void usb_free_td(volatile byte* td);
+
+void usb_free_itd(volatile byte* itd);
+
+void usb_free_bp(volatile byte* bp);
+
+bool usb_is_td(volatile byte* td);
+bool usb_is_itd(volatile byte* td);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,33 @@
+#include "mbed.h"
+#include "bd_addr.h"
+bd_addr::bd_addr()
+{
+
+}
+
+bd_addr::bd_addr(char* s)
+{
+    for(int i = 0; i <= 5; i++) {
+        ad[i] = strtol(s+i*3, NULL, 16);
+    }
+}
+
+uint8_t* bd_addr::data(uint8_t* addr)
+{
+    if (addr != NULL) {
+        ad[5] = addr[0];
+        ad[4] = addr[1];
+        ad[3] = addr[2];
+        ad[2] = addr[3];
+        ad[1] = addr[4];
+        ad[0] = addr[5];
+    }
+    return ad;
+}
+
+char* bd_addr::to_str()
+{
+    snprintf(ad_str, sizeof(ad_str), "%02X:%02X:%02X:%02X:%02X:%02X", 
+        ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
+    return ad_str;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,13 @@
+#ifndef BD_ADDR_H
+#define BD_ADDR_H
+class bd_addr {
+public:
+    bd_addr();
+    bd_addr(char* s);
+    uint8_t* data(uint8_t* addr = NULL);
+    char* to_str();
+private:
+    char ad_str[18];
+    uint8_t ad[6];
+};
+#endif //BD_ADDR_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/usbbt.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,220 @@
+#include "usbbt.h"
+//#define __DEBUG
+#include "mydbg.h"
+#include "Utils.h"
+
+usbbt::usbbt(int dongle)
+    : m_dongle(dongle),m_pEpIntIn(NULL),m_pEpBulkIn(NULL),m_pEpBulkOut(NULL),
+    m_int_seq(0),m_bulk_seq(0)
+{
+
+}
+
+int usbbt::setup(int timeout)
+{
+    for(int i = 0; i < 2; i++) {
+        m_pDev = m_pHost->getDeviceByClass(0xe0, m_dongle); 
+        if (m_pDev || i > 0) {
+            break;
+        }
+        UsbErr rc = Usb_poll();
+        if (rc == USBERR_PROCESSING) {
+            VERBOSE("%p USBERR_PROCESSING\n", this);
+            return -1;
+        }
+    }
+    DBG("m_pDev=%p\n", m_pDev);
+    if (m_pDev == NULL) {
+        VERBOSE("%p Bluetooth dongle(%d) NOT FOUND\n", this, m_dongle);
+        return -1;
+    }
+    DBG_ASSERT(m_pDev);
+
+    ParseConfiguration();
+    return 0;
+}
+
+int usbbt::ParseConfiguration()
+{
+  UsbErr rc;
+  uint8_t ConfigDesc[9];
+  int index = 0;
+  DBG_ASSERT(m_pDev);
+  rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_BYTES("ConfigDescriptor 9bytes", ConfigDesc, sizeof(ConfigDesc));
+  DBG_ASSERT(ConfigDesc[0] == 9);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  int wTotalLength = *((uint16_t*)&ConfigDesc[2]);
+  DBG("TotalLength: %d\n", wTotalLength);
+  int bConfigValue = ConfigDesc[5];
+  DBG_ASSERT(bConfigValue == 1);
+  DBG("ConfigValue: %d\n", bConfigValue);
+  VERBOSE("MaxPower: %d mA\n", ConfigDesc[8]*2);   
+
+  uint8_t* buf = new uint8_t[wTotalLength];
+  DBG_ASSERT(buf);
+  rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, wTotalLength);
+  DBG_ASSERT(rc == USBERR_OK);
+  DBG_ASSERT(ConfigDesc[1] == 0x02);
+  for (int pos = 0; pos < wTotalLength; pos += buf[pos]) {
+      DBG_BYTES("CFG", buf+pos, buf[pos]);
+      int type = buf[pos+1];
+      if (USB_DESCRIPTOR_TYPE_INTERFACE == type) { // 0x04
+        DBG("InterfaceNumber: %d\n", buf[pos+2]);
+        DBG("AlternateSetting: %d\n", buf[pos+3]);
+        DBG("NumEndpoint: %d\n", buf[pos+4]);
+        VERBOSE("InterfaceClass: %02X\n", buf[pos+5]);
+        VERBOSE("InterfaceSubClass: %02X\n", buf[pos+6]);
+        VERBOSE("InterfaceProtocol: %02X\n", buf[pos+7]);
+        DBG_ASSERT(buf[pos+6] == 0x01);
+        DBG_ASSERT(buf[pos+7] == 0x01);
+      } 
+      if (USB_DESCRIPTOR_TYPE_ENDPOINT == type) {
+          DBG_ASSERT(buf[pos] == 7);
+          uint8_t att = buf[pos+3];
+          uint8_t ep = buf[pos+2];
+          bool dir = ep & 0x80; // true=IN
+          uint16_t size = LE16(buf+pos+4);
+          DBG("EndpointAddress: %02X\n", ep);
+          DBG("Attribute: %02X\n", att);
+          DBG("MaxPacketSize: %d\n", size); 
+          UsbEndpoint* pEp = new UsbEndpoint(m_pDev, ep, dir, att == 3 ? USB_INT : USB_BULK, size);
+          DBG_ASSERT(pEp);
+          if (att == 3) { // interrupt
+              if (m_pEpIntIn == NULL) {
+                  m_pEpIntIn = pEp;
+              }
+          } else if (att == 2) { // bulk
+              if (dir) {
+                  if (m_pEpBulkIn == NULL) {
+                      m_pEpBulkIn = pEp;
+                  }
+              } else {
+                  if (m_pEpBulkOut == NULL) {
+                      m_pEpBulkOut = pEp;
+                  }
+              } 
+          }
+      }
+      if (m_pEpIntIn && m_pEpBulkIn && m_pEpBulkOut) { // cut off
+          break;
+      }
+  }
+  delete[] buf;
+  DBG_ASSERT(m_pEpIntIn);
+  DBG_ASSERT(m_pEpBulkIn);
+  DBG_ASSERT(m_pEpBulkOut);
+  return 0;   
+}
+
+int usbbt::send_packet(uint8_t packet_type, uint8_t* packet, int size)
+{
+    //DBG("\npacket_type=%d\n", packet_type);
+    //DBG_HEX(packet, size);
+
+    int rc;
+    switch(packet_type){
+        case HCI_COMMAND_DATA_PACKET:
+            DBG_ASSERT(m_pDev);
+            DBG_BYTES("\nCMD", packet, size);
+            rc = m_pDev->controlSend(
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_DEVICE, 
+                    0, 0, 0, packet, size);
+            DBG_ASSERT(rc == USBERR_OK);
+            return 0;
+        case HCI_ACL_DATA_PACKET:
+            DBG_ASSERT(m_pEpBulkOut);
+            DBG_BYTES("\nACL", packet, size);
+            rc = m_pEpBulkOut->transfer(packet, size);
+            DBG_ASSERT(rc == USBERR_PROCESSING);
+            while(m_pEpBulkOut->status() == USBERR_PROCESSING){
+                wait_us(1);
+            }
+            return 0;
+        default:
+            DBG_ASSERT(0);
+            return -1;
+    }
+}
+
+
+void usbbt::poll()
+{
+    //DBG("m_int_seq=%d\n", m_int_seq);
+    int rc, len;
+    switch(m_int_seq) {
+        case 0:
+            m_int_seq++;
+            break;
+        case 1:
+            rc = m_pEpIntIn->transfer(m_int_buf, sizeof(m_int_buf));
+            DBG_ASSERT(rc == USBERR_PROCESSING);
+            m_int_seq++;
+            break;
+        case 2:
+            len = m_pEpIntIn->status();
+            if (len == USBERR_PROCESSING) {
+                break;
+            }
+            if (len >= 0) {
+                //DBG("len=%d\n", len);
+                //DBG_HEX(m_int_buf, len);
+                onPacket(HCI_EVENT_PACKET, m_int_buf, len);
+                m_int_seq = 0;
+                break;
+            }
+            DBG_ASSERT(0);
+            break;
+    } 
+
+    switch(m_bulk_seq) {
+        case 0:
+            m_bulk_seq++;
+            break;
+        case 1:
+            rc = m_pEpBulkIn->transfer(m_bulk_buf, sizeof(m_bulk_buf));
+            DBG_ASSERT(rc == USBERR_PROCESSING);
+            m_bulk_seq++;
+            break;
+        case 2:
+            len = m_pEpBulkIn->status();
+            if (len == USBERR_PROCESSING) {
+                break;
+            }
+            if (len >= 0) {
+                //DBG("len=%d\n", len);
+                //DBG_HEX(m_bulk_buf, len);
+                onPacket(HCI_ACL_DATA_PACKET, m_bulk_buf, len);
+                m_bulk_seq = 0;
+                break;
+            }
+            DBG_ASSERT(0);
+            break;
+    } 
+}
+
+void usbbt::onPacket(uint8_t packet_type, uint8_t* packet, uint16_t size)
+{
+  DBG("\npacket_type=%d packet=%p size=%d\n", packet_type, packet, size);
+  DBG_HEX(packet, size);
+
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(packet_type, packet, size);
+  else if(m_pCb)
+    m_pCb(packet_type, packet, size);
+}
+
+void usbbt::setOnPacket( void (*pMethod)(uint8_t, uint8_t*, uint16_t) )
+{
+  m_pCb = pMethod;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void usbbt::clearOnPacket()
+{
+  m_pCb = NULL;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/usbbt.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,55 @@
+#ifndef USBBT_H
+#define USBBT_H
+#include "UsbHostMgr.h"
+#include "UsbEndpoint.h"
+#include "UsbBaseClass.h"
+
+#define HCI_COMMAND_DATA_PACKET	0x01
+#define HCI_ACL_DATA_PACKET	    0x02
+#define HCI_SCO_DATA_PACKET	    0x03
+#define HCI_EVENT_PACKET	    0x04
+
+class usbbt : public UsbBaseClass {
+public:
+    usbbt(int dongle = 0);
+    int setup(int timeout = 9000);
+    int send_packet(uint8_t packet_type, uint8_t* packet, int size);
+    void poll();
+    ///Setups the result callback
+    /**
+     @param pMethod : callback function
+     */
+    void setOnPacket( void (*pMethod)(uint8_t, uint8_t*, uint16_t) );
+  
+    ///Setups the result callback
+    /**
+    @param pItem : instance of class on which to execute the callback method
+    @param pMethod : callback method
+    */
+    class CDummy;
+    template<class T> 
+    void setOnPacket( T* pItem, void (T::*pMethod)(uint8_t, uint8_t*, uint16_t) )
+    {
+        m_pCb = NULL;
+        m_pCbItem = (CDummy*) pItem;
+        m_pCbMeth = (void (CDummy::*)(uint8_t, uint8_t*, uint16_t)) pMethod;
+    }
+    void clearOnPacket();
+private:
+    int ParseConfiguration();
+    void onPacket(uint8_t packet_type, uint8_t* packet, uint16_t size);
+    int m_dongle;
+    UsbDevice* m_pDev;
+    UsbEndpoint* m_pEpIntIn;
+    UsbEndpoint* m_pEpBulkIn;
+    UsbEndpoint* m_pEpBulkOut;
+    Timer m_timer;
+    int m_int_seq;
+    uint8_t m_int_buf[64];
+    int m_bulk_seq;
+    uint8_t m_bulk_buf[64];
+    CDummy* m_pCbItem;
+    void (CDummy::*m_pCbMeth)(uint8_t, uint8_t*, uint16_t);
+    void (*m_pCb)(uint8_t, uint8_t*, uint16_t);
+};
+#endif //USBBT_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/myjpeg.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,252 @@
+#include "mbed.h"
+//#define __DEBUG
+#include "mydbg.h"
+#include "myjpeg.h"
+
+static const uint8_t dht[] = {
+0xFF,0xC4,0x01,0xA2,0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
+0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
+0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x10,0x00,
+0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7D,0x01,
+0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,
+0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,
+0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,
+0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,
+0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,
+0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,
+0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,
+0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,0xE3,
+0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
+0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,
+0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,
+0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,
+0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,
+0x1A,0x26,0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,
+0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,
+0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,
+0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,
+0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,
+0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,
+0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,
+0xF7,0xF8,0xF9,0xFA,
+};
+
+myjpeg::myjpeg(uint8_t* buf, int len, int capacity)
+{
+    DBG_ASSERT(buf);
+    DBG_ASSERT(len >= 0);
+    m_buf = buf;
+    m_len = len;
+    m_capacity = capacity;
+}
+
+int myjpeg::getc()
+{
+    if (m_pos >= m_len) {
+        return -1;
+    }
+    return m_buf[m_pos++];    
+}
+
+int myjpeg::getBE16()
+{
+    int c1 = getc();
+    if (c1 == (-1)) {
+        return -1;
+    }
+    int c2 = getc();
+    if (c2 == (-1)) {
+        return -1;
+    }
+    return c1<<8|c2;
+}
+
+void myjpeg::analytics()
+{
+    m_pos = 0;
+    SOS_pos = 0;
+    DHT_pos = 0;
+    int skip;
+    int lp;
+    while(1) {
+        int marker_pos = m_pos;
+        int c = getc();
+        if (c == (-1)) {
+            break;
+        }
+        if (c != 0xff) {
+            continue;
+        }
+        c = getc();
+        if (c == (-1)) {
+            break;
+        }
+        uint8_t marker = c;
+        switch(marker) {
+            case 0xd8: 
+                DBG("%04X SOI\n", marker_pos);
+                skip = 0;
+                break;
+            case 0xd9: 
+                DBG("%04X EOI\n", marker_pos);
+                skip = 0;  
+                break;
+            case 0x00:
+                skip = 0;
+                break;
+            case 0xc0:
+                lp = getBE16();
+                DBG("%04X SOF0 %d\n", marker_pos, lp);
+                skip = lp - 2;
+                break;
+            case 0xc4:
+                lp = getBE16();
+                DBG("%04X DHT Lh: %d\n", marker_pos, lp);
+                //DBG("Tc: %d\n", buf[pos+2]>>4);
+                //DBG("Th: %d\n", buf[pos+2]&0xf);
+                DHT_pos = marker_pos;
+                skip = lp - 2;
+                break;
+            case 0xda:
+                lp = getBE16();
+                DBG("%04X SOS Ls: %d\n", marker_pos, lp);
+                //DBG("Ns: %d\n", buf[pos+2]);
+                //for(i = 1; i <= buf[pos+2]; i++) {
+                //    DBG("Cs%d: %d\n", i, buf[pos+3+(i-1)*2]);
+                //    DBG("Td%d: %d\n", i, buf[pos+4+(i-1)*2]>>4);
+                //    DBG("Ta%d: %d\n", i, buf[pos+4+(i-1)*2]&0xf);
+                //}
+                SOS_pos = marker_pos;
+                skip = lp - 2;
+                break;
+            case 0xdb:
+                lp = getBE16();
+                DBG("%04X DQT %d\n", marker_pos, lp);
+                skip = lp - 2;
+                break;
+            case 0xe0: 
+                lp = getBE16();
+                DBG("%04X APP0 %d\n", marker_pos, lp);
+                skip = lp - 2;
+                break;
+            default:
+                DBG("%04X ??? %02X\n", marker_pos, marker);
+                skip = 0;
+                break;
+        }
+        while(skip-- > 0) {
+            getc();
+        }
+    }
+}
+
+int myjpeg::insertDHT()
+{
+    DBG("m_len=%d m_capacity=%d SOS=%d\n", m_len, m_capacity, SOS_pos);
+    DBG_ASSERT(SOS_pos > 0);
+    DBG_ASSERT(SOS_pos < m_len);
+    DBG_ASSERT(m_len <= m_capacity);
+    DBG_ASSERT(sizeof(dht) == 420);
+    
+    int num1 = m_len - SOS_pos;
+    if (num1 > (m_capacity - SOS_pos - sizeof(dht))) {
+        num1 = m_capacity - SOS_pos - sizeof(dht);
+    }
+    DBG("num1=%d\n", num1);
+    DBG_ASSERT(SOS_pos+sizeof(dht)+num1 <= m_capacity);
+    memmove(m_buf+SOS_pos+sizeof(dht), m_buf+SOS_pos, num1);
+
+    int num2 = sizeof(dht);
+    if (num2 > m_capacity - SOS_pos) {
+        num2 = m_capacity - SOS_pos;
+    } 
+    DBG("num2=%d\n", num2);
+    DBG_ASSERT(SOS_pos+num2 <= m_capacity);
+    memcpy(m_buf+SOS_pos, dht, num2);
+    m_len += sizeof(dht);
+    if (m_len > m_capacity) {
+        m_len = m_capacity;
+    }
+    return m_len;
+}
+
+int fgetBE16(FILE* fp)
+{
+    int c1 = fgetc(fp);
+    if (c1 == EOF) {
+        return -1;
+    }
+    int c2 = fgetc(fp);
+    if (c2 == EOF) {
+        return -1;
+    }
+    return c1<<8|c2;
+}
+
+void QcamCopy(const char* destination, const char* source)
+{
+    FILE* fp;
+    FILE* fp2;
+    fp = fopen(source, "rb");
+    if (fp == NULL) {
+        return;
+    }
+    fp2 = fopen(destination, "wb");
+    if (fp2 == NULL) {
+        return;
+    }
+    int i,c1,c2;
+    bool f_dht = false;
+    bool f_lp = false;
+    while(!feof(fp)){
+        c1 = fgetc(fp);
+        if (c1 != 0xff) {
+            fputc(c1, fp2);
+            continue;
+        }
+        c2 = fgetc(fp);
+        switch(c2) {
+            case 0xda: // SOS
+                if (!f_dht) {
+                    for(i = 0; i < sizeof(dht); i++) {
+                        fputc(dht[i], fp2);
+                    }
+                    f_dht = true;
+                }
+                f_lp = true;
+                break;
+            case 0xc4: // DHT
+                f_dht = true;
+                f_lp = true;
+                break;
+            case 0xc0:
+            case 0xdb:
+            case 0xe0:
+                f_lp = true;
+                break;
+            default:
+                f_lp = false;
+                break;
+        }
+        fputc(c1, fp2); 
+        fputc(c2, fp2); // marker
+        if (f_lp) {
+            c1 = fgetc(fp); // length
+            c2 = fgetc(fp);
+            fputc(c1, fp2);
+            fputc(c2, fp2);
+            int skip = c1<<8|c2;
+            while(skip-- > 2) {
+                int c = fgetc(fp);
+                if (c == EOF) {
+                    break;
+                }
+                fputc(c, fp2);
+            }
+        }
+    }
+    fclose(fp);
+    fclose(fp2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/myjpeg.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,21 @@
+#ifndef MYJPEG_H
+#define MYJPEG_H
+class myjpeg {
+public:
+    myjpeg(uint8_t* buf, int len, int capacity);
+    void analytics();
+    int insertDHT();
+    int SOS_pos;
+    int DHT_pos;
+private:
+    int getc();
+    int getBE16();
+    uint8_t* m_buf;
+    int m_len;
+    int m_pos;
+    int m_capacity;
+};
+
+void QcamCopy(const char* destination, const char* source);
+
+#endif //MYJPEG_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/stcamcfg.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,25 @@
+#ifndef STCAMCFG_H
+#define STCAMCFG_H
+struct stcamcfg {
+    uint16_t idVender;
+    uint16_t idProduct;
+    uint16_t width;
+    uint16_t height;
+    uint8_t payload;
+    uint8_t bEndpointAddress; 
+    uint16_t wMaxPacketSize;
+    uint8_t FormatIndex;
+    uint8_t FrameIndex;
+    uint32_t dwFrameInterval;
+    uint8_t bInterface;
+    uint8_t bAlternate;
+    char *name;
+    int iso_FrameCount;
+    int iso_itdCount;
+    // work area
+    int _If;
+    int _Ifalt;
+    int _IfClass;
+    int _IfSubClass;
+};
+#endif //STCAMCFG_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/usb_itd.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,117 @@
+#include "mbed.h"
+#include "usb_itd.h"
+#define __DEBUG
+#include "mydbg.h"
+
+usb_itd::usb_itd(HCITD* itd)
+{
+    DBG_ASSERT(itd);
+    m_itd = itd;
+}
+
+bool usb_itd::Done()
+{
+    int cc = (m_itd->Control >> 28);
+    if (cc == 0xe || cc == 0xf) { // not accessed?
+        return false;
+    }
+    if (m_itd->Next) {
+        return false;
+    }
+    return true;
+}
+
+int usb_itd::ConditionCode()
+{
+    int cc = (m_itd->Control >> 28);
+    return cc;
+}
+
+uint16_t usb_itd::get_psw(int n)
+{
+    DBG_ASSERT(n >= 0 && n <= 7);
+    DBG_ASSERT(m_itd);
+    uint16_t psw = 0;
+    switch(n) {
+        case 0: psw = m_itd->OffsetPSW10;       break;
+        case 1: psw = m_itd->OffsetPSW10 >> 16; break;
+        case 2: psw = m_itd->OffsetPSW32;       break;
+        case 3: psw = m_itd->OffsetPSW32 >> 16; break;
+        case 4: psw = m_itd->OffsetPSW54;       break;
+        case 5: psw = m_itd->OffsetPSW54 >> 16; break;
+        case 6: psw = m_itd->OffsetPSW76;       break;
+        case 7: psw = m_itd->OffsetPSW76 >> 16; break;
+    }
+    return psw;
+}
+
+uint16_t usb_itd::StartingFrame()
+{
+    return (m_itd->Control & ITD_SF);
+}
+
+int usb_itd::FrameCount()
+{
+    DBG_ASSERT(m_itd);
+    int fc = ((m_itd->Control & ITD_FC) >> 24) + 1;
+    DBG_ASSERT(fc >= 1 && fc <= 8); 
+    return fc; 
+}
+
+int usb_itd::PacketStatus(int n)
+{
+    DBG_ASSERT(n >=0 && n <= 7);
+    uint16_t psw = get_psw(n);
+    int cc = (psw >> 12) & 0xf;
+    return cc;
+}
+
+int usb_itd::Length(int n)
+{
+    DBG_ASSERT(n >=0 && n <= 7);
+    uint16_t psw = get_psw(n);
+    int size = psw & 0x7ff;
+    int cc = (psw >> 12) & 0xf;
+    if (cc == 0xe || cc == 0xf) {
+        return -1;
+    }
+    if (cc == 0 || cc == 9) {
+        return size;
+    }
+    debug();
+    return -1;
+}
+
+uint8_t* usb_itd::BufferPage(int n, int size)
+{
+    DBG_ASSERT(n >=0 && n <= 7);
+    DBG_ASSERT(size >= 128 && size <= 956);
+    uint8_t* buf = (uint8_t*)m_itd->BufferPage0 + n * size;
+    DBG_ASSERT((uint32_t)(buf+size-1) <= m_itd->BufferEnd);
+    return buf;
+}
+
+void usb_itd::free()
+{
+    DBG_ASSERT(m_itd);
+    if (m_itd) {
+        uint8_t* buf = (uint8_t*)m_itd->BufferPage0;
+        DBG_ASSERT(buf);
+        usb_free_bp(buf);
+        usb_free_itd((byte*)m_itd);
+        m_itd = NULL;
+    }
+}
+
+void usb_itd::debug()
+{
+    DBG("itd             =%08X\n", m_itd);
+    DBG("itd->Control    =%08X\n", m_itd->Control);
+    DBG("itd->BufferPage0=%08X\n", m_itd->BufferPage0); 
+    DBG("itd->Next       =%08X\n", m_itd->Next); 
+    DBG("itd->BufferEnd  =%08X\n", m_itd->BufferEnd); 
+    DBG("itd->OffsetPSW10=%08X\n", m_itd->OffsetPSW10);
+    DBG("itd->OffsetPSW32=%08X\n", m_itd->OffsetPSW32);
+    DBG("itd->OffsetPSW54=%08X\n", m_itd->OffsetPSW54);
+    DBG("itd->OffsetPSW76=%08X\n", m_itd->OffsetPSW76);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/usb_itd.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,23 @@
+#ifndef USB_ITD_H
+#define USB_ITD_H
+#include "UsbInc.h"
+#include "usb_mem.h"
+
+class usb_itd {
+public:
+    usb_itd(HCITD* itd);
+    bool Done();
+    int ConditionCode();
+    int FrameCount();
+    int PacketStatus(int n);
+    int Length(int n);
+    uint8_t* BufferPage(int n, int size);
+    uint16_t StartingFrame();
+    void free();
+    void debug();
+private:
+    uint16_t get_psw(int n);
+    HCITD* m_itd;
+};
+
+#endif //USB_ITD_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/usb_mjpeg.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,143 @@
+#include "mbed.h"
+#include "usb_mjpeg.h"
+//#define __DEBUG
+#define __DEBUG2
+#include "mydbg.h"
+#include "Utils.h"
+#include "myjpeg.h"
+
+#ifdef __DEBUG
+extern DigitalOut led4;
+#endif // __DEBUG
+
+#define MJPEG_FID 0x01
+#define MJPEG_EOF 0x02
+#define MJPEG_PTS 0x04
+#define MJPEG_SCR 0x08
+#define MJPEG_STI 0x20
+#define MJPEG_ERR 0x40
+#define MJPEG_EOH 0x80
+
+
+usb_mjpeg::usb_mjpeg(uint8_t* buf, int size)
+{
+    DBG_ASSERT(size >= 1024 && size <= 16000);
+    m_size = size;
+    m_seq = 0;
+    m_buf = buf;
+    ReportErrorFID = 0;
+    ReportErrorPTS = 0;
+}
+
+usb_mjpeg::~usb_mjpeg()
+{
+
+}
+
+void usb_mjpeg::input(uint16_t frame, uint8_t* buf, int len)
+{
+    uint8_t* StreamHeader = buf;
+    DBG_ASSERT(buf);
+    if (len > 12) {
+        //DBG_PRINTF("%d %02X %d\n", frame, buf[1], len);
+        //DBG_HEX(buf, len);
+        DBG_ASSERT(StreamHeader[0] == 0x0c);
+        //DBG_ASSERT(buf[1] == 0x8c || buf[1] == 0x8d);
+        //DBG("bfh:%02X\n", buf[1]);
+    }
+    DBG_ASSERT(len >= 2);
+
+    int hle = StreamHeader[0];
+    uint8_t bfh = StreamHeader[1];
+    DBG_ASSERT(len >= hle);
+    DBG_ASSERT(hle == 12);
+    uint8_t* data = buf + hle;
+    int data_len = len - hle;
+    if (m_seq == 0) {
+        if (check_SOI(buf, len)) {
+            DBG_PRINTF("%04X SOI\n", frame);
+            DBG_BYTES("SOI", buf, 16);
+            _open();
+            m_bfh = bfh; // save FID
+            if (bfh & MJPEG_PTS) {
+                m_pts = LE32(StreamHeader+2); // save PTS
+            }
+            _wrtie(data, data_len);
+            m_seq++;
+        }
+    } else if (m_seq == 1) {
+        if (len > hle) {
+            _wrtie(data, data_len);
+        }
+        if (check_EOI(buf, len)) {
+            DBG_PRINTF("%04X EOI\n", frame);
+            DBG_BYTES("EOI", buf, 12);
+            _close();
+            m_seq = 2; // done
+        } else if ((m_bfh ^ bfh) & MJPEG_FID) {
+            ReportErrorFID++;
+            DBG("ReportErrorFID=%d\n", ReportErrorFID);
+            m_seq = 0; // restart
+        } else if ((bfh & MJPEG_PTS) && m_pts != LE32(StreamHeader+2)) {
+            ReportErrorPTS++;
+            DBG("ReportErrorPTS=%d\n", ReportErrorPTS);
+            m_seq = 0; //  restart
+        }
+    } else { // done
+    }
+    DBG_LED4(buf[1] & MJPEG_FID); // FID
+}
+
+int usb_mjpeg::status()
+{
+    if (m_seq <= 1) {
+        return USBERR_PROCESSING;
+    }    
+    return m_pos;
+}
+
+bool usb_mjpeg::check_SOI(uint8_t* buf, int len)
+{
+    if (len >= (12+2)) {
+        if (buf[12] == 0xff && buf[13] == 0xd8) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool usb_mjpeg::check_EOI(uint8_t* buf, int len)
+{
+    if (len >= 12) {
+        if (buf[1] & MJPEG_EOF) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void usb_mjpeg::_open()
+{
+    m_pos = 0;
+}
+
+void usb_mjpeg::_wrtie(uint8_t* buf, int len)
+{
+    if (m_buf == NULL) {
+        return;
+    }
+    for(int i = 0; i < len && m_pos < m_size; i++) {
+        m_buf[m_pos++] = buf[i];
+    }
+}
+
+void usb_mjpeg::_close()
+{
+    //DBG("m_pos=%d\n", m_pos);
+    //DBG_HEX(m_buf, m_pos);
+    myjpeg JPEG(m_buf, m_pos, m_size);
+    JPEG.analytics();
+    if (JPEG.DHT_pos == 0) {
+        m_pos = JPEG.insertDHT();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/usb_mjpeg.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,33 @@
+#ifndef USB_MJPEG_H
+#define USB_MJPEG_H
+#include "UsbInc.h"
+
+class usb_stream {
+public:
+    virtual void input(uint16_t frame, uint8_t* buf, int len) = 0;
+};
+
+class usb_mjpeg : public usb_stream {
+public:
+    usb_mjpeg(uint8_t* buf = NULL, int size = 4800);
+    ~usb_mjpeg();
+    virtual void input(uint16_t frame, uint8_t* buf, int len);
+    int status();
+    uint16_t ReportErrorFID;
+    uint16_t ReportErrorPTS;
+private:
+    void _open();
+    void _wrtie(uint8_t* buf, int len);
+    void _close();
+
+    uint8_t* m_buf;
+    int m_pos;
+    bool check_SOI(uint8_t* buf, int len);
+    bool check_EOI(uint8_t* buf, int len);
+    void analyticsJPEG(uint8_t* buf, int len);
+    int m_seq;
+    int m_size;
+    uint8_t m_bfh;
+    uint32_t m_pts; 
+};
+#endif //USB_MJPEG_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvc.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,264 @@
+#include "mbed.h"
+#include "uvc.h"
+
+//#define __DEBUG
+//#define __DEBUG3
+#include "mydbg.h"
+#include "usb_itd.h"
+
+uvc::uvc(int cam)
+{
+    DBG("cam=%d\n", cam);
+    DBG_ASSERT(cam >= 0);
+    m_cam = cam;
+    m_init = false;
+    m_connect = false;
+    m_int_seq = 0;
+    m_iso_seq = 0;
+    m_width = 0;
+    m_height = 0;
+    m_payload = PAYLOAD_MJPEG;
+    m_FormatIndex = 0;
+    m_FrameIndex = 0;
+    m_FrameInterval = 0;
+    m_PacketSize = 0;
+    m_stream = NULL;
+    for(int i = 0; i <= 15; i++) {
+        ReportConditionCode[i] = 0;
+    }
+    clearOnResult();
+}
+
+uvc::~uvc()
+{
+    clearOnResult();
+}
+
+int uvc::setup()
+{
+    if (!m_init) {
+        return _init();
+    }
+    return 0;
+}
+
+int uvc::get_jpeg(const char* path)
+{
+    const int size = 4800;
+    const int timeout = 5000;
+    uint8_t* buf = new uint8_t[size];
+    DBG_ASSERT(buf);
+    if (buf == NULL) {
+        return -1;
+    }
+    usb_mjpeg mjpeg(buf, size);
+    attach(&mjpeg);
+    Timer t;
+    t.reset();
+    t.start();
+    while(t.read_ms() < timeout) {
+        int stat = isochronous();
+        if (mjpeg.status() >= 0) {
+            break;
+        }
+    }
+    detach();
+    int len = mjpeg.status();
+    if (len >= 0) {
+        if (path != NULL) {
+            FILE *fp = fopen(path, "wb");
+            if (fp != NULL) {
+                for(int i = 0; i < len; i++) {
+                    fputc(buf[i], fp);
+                }
+                fclose(fp);
+            }
+        }    
+    }
+    delete[] buf;
+    return len;
+}
+
+int uvc::get_jpeg(uint8_t* buf, int size)
+{
+    //DBG("buf=%p size=%d\n", buf, size);
+    const int timeout = 5000;
+    usb_mjpeg mjpeg(buf, size);
+    attach(&mjpeg);
+    Timer t;
+    t.reset();
+    t.start();
+    while(t.read_ms() < timeout) {
+        int stat = isochronous();
+        if (mjpeg.status() >= 0) {
+            break;
+        }
+    }
+    detach();
+    int len = mjpeg.status();
+    return len;
+}
+
+bool uvc::interrupt()
+{
+    if (!m_init) {
+        _init();
+    }
+    if (m_int_seq == 0) {
+        int rc = m_pEpIntIn->transfer(m_int_buf, sizeof(m_int_buf));
+        if (rc != USBERR_PROCESSING) {
+            return false;
+        }
+        m_int_seq++;
+    }
+    int len = m_pEpIntIn->status();
+    if (len > 0) {
+        m_int_seq = 0;
+        DBG_BYTES("interrupt", m_int_buf, len);
+        return true;
+    }
+    return false;
+}
+
+#define CC_NOERROR      0x0
+#define CC_DATAOVERRUN  0x8
+#define CC_DATAUNDERRUN 0x9
+
+inline void DI()
+{
+    NVIC_DisableIRQ(USB_IRQn);
+}
+
+inline void EI()
+{
+    NVIC_EnableIRQ(USB_IRQn);
+} 
+
+int uvc::isochronous()
+{
+    if (m_iso_seq == 0) {
+        uint16_t frame = LPC_USB->HcFmNumber;
+        m_iso_frame = frame + 10; // 10msec
+        DBG_ASSERT(m_pEpIsoIn->m_itdActive == 0);
+        m_iso_seq++;
+    }
+    if (m_iso_seq == 1) {
+        DBG_ASSERT(m_itdCount > 0 && m_itdCount <= 8);
+        while(m_pEpIsoIn->m_itdActive < m_itdCount) {
+            int len = m_PacketSize * m_FrameCount;
+            uint8_t* buf = (uint8_t*)usb_get_bp(len);
+            if (buf == NULL) {
+                DBG("len=%d\n", len);
+                DBG("m_itdCount=%d\n", m_itdCount);
+            }
+            DBG_ASSERT(buf);
+            int rc = m_pEpIsoIn->transfer(m_iso_frame, m_FrameCount, buf, len);
+            m_iso_frame += m_FrameCount;
+            DBG_ASSERT(rc == USBERR_PROCESSING);
+        }
+        m_iso_seq++;
+    }
+    if (m_iso_seq == 2) {
+        //DBG("frame:%04X\n", LPC_USB->HcFmNumber);
+        while(1) {
+            DI();
+            bool empty = m_pEpIsoIn->queue_done_itd.empty();
+            EI();
+            
+            if (empty) {
+                break;
+            }
+            
+            DI();
+            HCITD* itd = m_pEpIsoIn->queue_done_itd.front();
+            m_pEpIsoIn->queue_done_itd.pop();
+            EI();
+            
+            m_pEpIsoIn->m_itdActive--;
+            usb_itd iso_td(itd);
+            //DBG("frame:%04X\n", LPC_USB->HcFmNumber);
+            //DBG("itd->Control=%08X\n", itd->Control); 
+            int cc = iso_td.ConditionCode();
+            DBG_ASSERT(cc >= 0 && cc <= 15);
+            ReportConditionCode[cc]++;
+            if (cc != CC_NOERROR) {
+                DBG3("%04X ERR:%X\n", LPC_USB->HcFmNumber, cc);
+                iso_td.free();
+                m_iso_seq = 3;
+                return -1;
+            }
+            uint16_t frame = iso_td.StartingFrame();
+            int fc = iso_td.FrameCount();
+            for(int i = 0; i < fc; i++) {
+                int len = iso_td.Length(i);
+                if (len > 0) {
+                    if (m_stream) {
+                        m_stream->input(frame+i, iso_td.BufferPage(i, m_PacketSize), len);
+                    }
+                    onResult(frame+i, iso_td.BufferPage(i, m_PacketSize), len);
+                }
+            }
+            iso_td.free();
+        }
+        //DBG("frame:%04X\n", LPC_USB->HcFmNumber);
+        m_iso_seq = 1;
+        return m_pEpIsoIn->m_itdActive;
+    }
+    if (m_iso_seq == 3) { // cleanup
+        DBG("m_pEpIsoIn->queue_done_itd.size()  :%d\n", m_pEpIsoIn->queue_done_itd.size());
+        while(1) {
+            DI();
+            bool empty = m_pEpIsoIn->queue_done_itd.empty();
+            EI();
+            
+            if (empty) {
+                break;
+            }
+                       
+            DI();
+            HCITD* itd = m_pEpIsoIn->queue_done_itd.front();
+            m_pEpIsoIn->queue_done_itd.pop();
+            EI();
+            
+            m_pEpIsoIn->m_itdActive--;
+            usb_itd iso_td(itd);
+            iso_td.free();
+        }
+        if (m_pEpIsoIn->m_itdActive == 0) {
+            m_iso_seq = 0;
+        }
+    }
+    return m_pEpIsoIn->m_itdActive;
+}
+
+void uvc::attach(usb_stream* stream)
+{
+    m_stream = stream;
+}
+
+void uvc::detach()
+{
+    m_stream = NULL;
+}
+
+void uvc::onResult(uint16_t frame, uint8_t* buf, int len)
+{
+  if(m_pCbItem && m_pCbMeth)
+    (m_pCbItem->*m_pCbMeth)(frame, buf, len);
+  else if(m_pCb)
+    m_pCb(frame, buf, len);
+}
+
+void uvc::setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) )
+{
+  m_pCb = pMethod;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
+
+void uvc::clearOnResult()
+{
+  m_pCb = NULL;
+  m_pCbItem = NULL;
+  m_pCbMeth = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvc.h	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,102 @@
+#ifndef UVC_H
+#define UVC_H
+#include "UsbBaseClass.h"
+#include "usb_mem.h"
+#include "usb_mjpeg.h"
+
+#define CLASS_VIDEO 0x0E
+
+#define SET_CUR  0x01
+#define GET_CUR  0x81
+#define GET_MIN  0x82
+#define GET_MAX  0x83
+#define GET_RES  0x84
+#define GET_LEN  0x85
+#define GET_INFO 0x86
+#define GET_DEF  0x87
+
+#define VS_PROBE_CONTROL  0x01
+#define VS_COMMIT_CONTROL 0x02
+
+#define PAYLOAD_UNDEF 0
+#define PAYLOAD_MJPEG 1
+#define PAYLOAD_YUY2  2
+
+class uvc : public UsbBaseClass {
+public:
+    uvc(int cam = 0);
+    ~uvc();
+    int setup();
+    int get_jpeg(const char* path);
+    int get_jpeg(uint8_t* buf, int size);
+    bool interrupt();
+    int isochronous();
+    void attach(usb_stream* stream);
+    void detach();
+    ///set format index
+    void SetFormatIndex(int index = 1);
+    ///set frame index
+    void SetFrameIndex(int index = 1);
+    ///set frame interval
+    void SetFrameInterval(int val = 2000000);
+    ///set packet size
+    void SetPacketSize(int size = 128);
+    ///set image size
+    void SetImageSize(int width = 160, int height = 120);
+    ///set payload MJPEG or YUY2
+    void SetPayload(int payload); // MJPEG,YUV422(YUY2)
+    UsbErr Control(int req, int cs, int index, uint8_t* buf, int size);
+    ///Setups the result callback
+    /**
+     @param pMethod : callback function
+     */
+    void setOnResult( void (*pMethod)(uint16_t, uint8_t*, int) );
+  
+    ///Setups the result callback
+    /**
+    @param pItem : instance of class on which to execute the callback method
+    @param pMethod : callback method
+    */
+    class CDummy;
+    template<class T> 
+    void setOnResult( T* pItem, void (T::*pMethod)(uint16_t, uint8_t*, int) )
+    {
+        m_pCb = NULL;
+        m_pCbItem = (CDummy*) pItem;
+        m_pCbMeth = (void (CDummy::*)(uint16_t, uint8_t*, int)) pMethod;
+    }
+    void clearOnResult();
+
+    void poll();
+    void wait(float s);
+    void wait_ms(int ms);
+    uint16_t ReportConditionCode[16];
+protected:
+    int _init();
+    void _config(struct stcamcfg* cfg);
+    void onResult(uint16_t frame, uint8_t* buf, int len);
+    bool m_connect;
+    bool m_init;
+    int m_cam;
+    UsbDevice* m_pDev;
+    UsbEndpoint* m_pEpIntIn;
+    UsbEndpoint* m_pEpIsoIn;
+    int m_width;
+    int m_height;
+    int m_payload;
+    int m_FormatIndex;
+    int m_FrameIndex;
+    int m_FrameInterval;
+    int m_PacketSize;
+    int m_FrameCount; // 1-8
+    int m_itdCount;
+    uint8_t m_int_buf[16];
+    int m_int_seq;
+    int m_iso_seq;
+    uint16_t m_iso_frame;
+    usb_stream* m_stream;
+    CDummy* m_pCbItem;
+    void (CDummy::*m_pCbMeth)(uint16_t, uint8_t*, int);
+    void (*m_pCb)(uint16_t, uint8_t*, int);
+};
+#endif //UVC_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvccfg.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,401 @@
+#include "mbed.h"
+#include "uvc.h"
+#define __DEBUG
+#include "mydbg.h"
+#include "stcamcfg.h"
+#include "Utils.h"
+
+#define  DESCRIPTOR_TYPE_DEVICE        1
+#define  DESCRIPTOR_TYPE_CONFIGURATION 2
+#define  DESCRIPTOR_TYPE_STRING        3
+#define  DESCRIPTOR_TYPE_INTERFACE     4
+#define  DESCRIPTOR_TYPE_ENDPOINT      5
+
+#define DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0b
+
+#define DESCRIPTOR_TYPE_HID          0x21
+#define DESCRIPTOR_TYPE_REPORT       0x22
+#define DESCRIPTOR_TYPE_PHYSICAL     0x23
+#define DESCRIPTOR_TYPE_CS_INTERFACE 0x24
+#define DESCRIPTOR_TYPE_CS_ENDPOINT  0x25
+#define DESCRIPTOR_TYPE_HUB          0x29
+
+#define CLASS_AUDIO 0x02
+#define CLASS_HUB   0x09
+
+#define IF_EQ_THEN_PRINTF(A,B) if (A == B) {VERBOSE("%s\n", #A);
+#define ENDIF }
+
+#define AC_HEADER          0x01
+#define AC_INPUT_TERMINAL  0x02
+#define AC_OUTPUT_TERMINAL 0x03
+#define AC_FEATURE_UNIT    0x06
+
+// Input Terminal Types
+#define ITT_CAMERA 0x0201
+
+
+void _parserAudioControl(uint8_t* buf, int len) {
+    int subtype = buf[2];
+    IF_EQ_THEN_PRINTF(AC_HEADER, subtype)
+    VERBOSE("ADC: %04x\n", LE16(buf+3));
+    VERBOSE("TotalLength: %d\n", LE16(buf+5));
+    VERBOSE("InCollection: %d\n", buf[7]);
+    for (int n = 1; n <= buf[7]; n++) {
+        VERBOSE("aInterfaceNr(%d): %d\n", n, buf[8+n-1]);
+    }
+    ENDIF
+    IF_EQ_THEN_PRINTF(AC_INPUT_TERMINAL, subtype)
+    VERBOSE("TerminalID: %d\n", buf[3]);
+    VERBOSE("TerminalType: %04X\n", LE16(buf+4));
+    VERBOSE("AssocTermianl: %d\n", buf[6]);
+    VERBOSE("NrChannels: %d\n", buf[7]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(AC_OUTPUT_TERMINAL, subtype)
+    VERBOSE("TerminalID: %d\n", buf[3]);
+    VERBOSE("TerminalType: %04X\n", LE16(buf+4));
+    VERBOSE("AssocTermianl: %d\n", buf[6]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(AC_FEATURE_UNIT, subtype)
+    VERBOSE("UnitID: %d\n", buf[3]);
+    VERBOSE("SourceID: %d\n", buf[4]);
+    VERBOSE("ControlSize: %d\n", buf[5]);
+    ENDIF
+}
+
+#define AS_GENERAL     0x01
+#define AS_FORMAT_TYPE 0x02
+
+void _parserAudioStream(uint8_t* buf, int len) {
+    int subtype = buf[2];
+    IF_EQ_THEN_PRINTF(AS_GENERAL, subtype)
+    VERBOSE("TerminalLink: %d\n", buf[3]);
+    VERBOSE("Delay: %d\n", buf[4]);
+    VERBOSE("FormatTag: %04x\n", LE16(buf+5));
+    ENDIF
+    IF_EQ_THEN_PRINTF(AS_FORMAT_TYPE, subtype)
+    VERBOSE("FormatType: %d\n", buf[3]);
+    VERBOSE("NrChannels: %d\n", buf[4]);
+    VERBOSE("SubFrameSize: %d\n", buf[5]);
+    VERBOSE("BitResolution: %d\n", buf[6]);
+    VERBOSE("SamFreqType: %d\n", buf[7]);
+    VERBOSE("SamFreq(1): %d\n", LE24(buf+8));
+    ENDIF
+}
+
+#define CC_VIDEO 0x0e
+
+#define SC_VIDEOCONTROL   0x01
+#define SC_VIDEOSTREAMING 0x02
+
+#define VC_HEADER          0x01
+#define VC_INPUT_TERMINAL  0x02
+#define VC_OUTPUT_TERMINAL 0x03
+#define VC_SELECTOR_UNIT   0x04
+#define VC_PROCESSING_UNIT 0x05
+#define VC_EXTENSION_UNIT  0x06
+
+void _parserVideoControl(uint8_t* buf, int len) {
+    int subtype = buf[2];
+    IF_EQ_THEN_PRINTF(VC_HEADER, subtype)
+        VERBOSE("UVC: %04x\n", LE16(buf+3));
+        VERBOSE("TotalLength: %d\n", LE16(buf+5));
+        VERBOSE("ClockFrequency: %d\n", LE32(buf+7));
+        VERBOSE("InCollection: %d\n", buf[11]);
+        VERBOSE("aInterfaceNr(1): %d\n", buf[12]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(VC_INPUT_TERMINAL, subtype)
+        VERBOSE("TerminalID: %d\n", buf[3]);
+        uint16_t tt = LE16(buf+4);
+        VERBOSE("TerminalType: %04X\n", tt);
+        VERBOSE("AssocTerminal: %d\n", buf[6]);
+        VERBOSE("Terminal: %d\n", buf[7]);
+        if (tt == ITT_CAMERA) { // camera
+            int bControlSize = buf[14];
+            VERBOSE("ControlSize: %d\n", bControlSize);
+            for(int i = 0; i < bControlSize; i++) {
+            uint8_t bControls = buf[15+i];
+                VERBOSE("Controls(%d): %02X\n", i, bControls); 
+            }
+        }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VC_OUTPUT_TERMINAL, subtype)
+        VERBOSE("TerminalID: %d\n", buf[3]);
+        VERBOSE("TerminalType: %04X\n", LE16(buf+4));
+        VERBOSE("AssocTerminal: %d\n", buf[6]);
+        VERBOSE("SourceID: %d\n", buf[7]);
+        VERBOSE("Terminal: %d\n", buf[8]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(VC_SELECTOR_UNIT, subtype)
+        VERBOSE("UnitID: %d\n", buf[3]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(VC_PROCESSING_UNIT, subtype)
+        VERBOSE("UnitID: %d\n", buf[3]);
+        VERBOSE("SourceID: %d\n", buf[4]);
+        VERBOSE("MaxMultiplier: %d\n", LE16(buf+5));
+        VERBOSE("ControlSize: %d\n", buf[7]);
+        int pos = 8;
+        for (int n = 1; n <= buf[7]; n++) {
+            VERBOSE("Controls(%d): %02X\n", n , buf[pos]);
+            pos++;
+        }
+        VERBOSE("Processing: %d\n", buf[pos]);
+        pos++;
+        VERBOSE("VideoStanders: %02X\n", buf[pos]);
+    ENDIF
+    IF_EQ_THEN_PRINTF(VC_EXTENSION_UNIT, subtype)
+        VERBOSE("UnitID: %d\n", buf[3]);
+    ENDIF
+}
+
+#define VS_INPUT_HEADER 0x01
+#define VS_STILL_FRAME  0x03
+#define VS_FORMAT_UNCOMPRESSED 0x04
+#define VS_FRAME_UNCOMPRESSED 0x05
+#define VS_FORMAT_MJPEG 0x06
+#define VS_FRAME_MJPEG  0x07
+#define VS_COLOR_FORMAT 0x0d
+
+void _parserVideoStream(struct stcamcfg* cfg, uint8_t* buf, int len) {
+    int subtype = buf[2];
+    IF_EQ_THEN_PRINTF(VS_INPUT_HEADER, subtype)
+        VERBOSE("NumFormats: %d\n", buf[3]);
+        VERBOSE("TotalLength: %d\n", LE16(buf+4));
+        VERBOSE("EndpointAddress: %02X\n", buf[6]);
+        VERBOSE("Info: %02X\n", buf[7]);
+        VERBOSE("TerminalLink: %d\n", buf[8]);
+        VERBOSE("StillCaptureMethod: %d\n", buf[9]);
+        VERBOSE("TriggerSupport: %d\n", buf[10]);
+        VERBOSE("TriggerUsage: %d\n", buf[11]);
+        VERBOSE("ControlSize: %d\n", buf[12]);
+        int pos = 13;
+        for (int n = 1; n <= buf[12]; n++) {
+            VERBOSE("Controls(%d): %02X\n", n, buf[pos]);
+            pos++;
+        }
+        cfg->bEndpointAddress = buf[6];
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_STILL_FRAME, subtype)
+    VERBOSE("EndpointAdress: %02X\n", buf[3]);
+    VERBOSE("NumImageSizePatterns: %d\n", buf[4]);
+    int ptn = buf[4];
+    int pos = 5;
+    for (int n = 1; n <= ptn; n++) {
+        VERBOSE("Width(%d): %d\n", n, LE16(buf+pos));
+        VERBOSE("Height(%d): %d\n", n, LE16(buf+pos+2));
+        pos += 4;
+    }
+    VERBOSE("NumCompressPtn: %d\n", buf[pos]);
+    ptn = buf[pos++];
+    for (int n = 1; n <= ptn; n++) {
+        VERBOSE("Compress(%d): %d\n", n, buf[pos]);
+        pos++;
+    }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_FORMAT_UNCOMPRESSED, subtype)
+        VERBOSE("FormatIndex: %d\n", buf[3]);
+        VERBOSE("NumFrameDescriptors: %d\n", buf[4]);
+        uint32_t guid = LE32(buf+5);
+        if (guid == 0x32595559) {
+            VERBOSE("GUID: YUY2\n");
+        } else if (guid == 0x3231564e) {
+            VERBOSE("GUID: NV12\n");
+        } else {
+            VERBOSE("GUID: %08x\n", guid);
+        }
+        VERBOSE("DefaultFrameIndex: %d\n", buf[22]);
+        if (cfg->payload == PAYLOAD_YUY2) {
+            cfg->FormatIndex = buf[3];
+        }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_FRAME_UNCOMPRESSED, subtype)
+        VERBOSE("FrameIndex: %d\n", buf[3]);
+        VERBOSE("Capabilites: %d\n", buf[4]);
+        VERBOSE("Width: %d\n", LE16(buf+5));
+        VERBOSE("Height: %d\n", LE16(buf+7));
+        VERBOSE("MinBitRate: %d\n", LE32(buf+9));
+        VERBOSE("MaxBitRate: %d\n", LE32(buf+13));
+        VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17));
+        VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21));
+        VERBOSE("FrameIntervalType: %d\n", buf[25]);
+        int it = buf[25];
+        uint32_t max_fi = 333333; // 30.0fps
+        if (it == 0) {
+            VERBOSE("FrameMinInterval: %d\n", buf[26]);
+            VERBOSE("FrameMaxInterval: %d\n", buf[30]);
+            VERBOSE("FrameIntervalStep: %d\n", buf[34]);
+        } else {
+            int pos = 26;
+            for (int n = 1; n <= it; n++) {
+                uint32_t fi = LE32(buf+pos);
+                if (fi >= max_fi) {
+                    max_fi = fi;
+                }
+                float fps = 1e+7 / fi;
+                VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps);
+                pos += 4;
+            }
+        }
+        if (cfg->payload == PAYLOAD_YUY2) {
+            if (cfg->width == LE16(buf+5) && cfg->height == LE16(buf+7)) {
+                cfg->FrameIndex = buf[3];
+            }
+            if (cfg->dwFrameInterval == 0) {
+                cfg->dwFrameInterval = max_fi;
+            }
+        }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_FORMAT_MJPEG, subtype)
+        VERBOSE("FormatIndex: %d\n", buf[3]);
+        VERBOSE("NumFrameDescriptors: %d\n", buf[4]);
+        VERBOSE("Flags: %d\n", buf[5]);
+        VERBOSE("DefaultFrameIndex: %d\n", buf[6]);
+        if (cfg->payload == PAYLOAD_MJPEG) {
+            cfg->FormatIndex = buf[3];
+        }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_FRAME_MJPEG, subtype)
+        VERBOSE("FrameIndex: %d\n", buf[3]);
+        VERBOSE("Capabilites: %d\n", buf[4]);
+        VERBOSE("Width: %d\n", LE16(buf+5));
+        VERBOSE("Height: %d\n", LE16(buf+7));
+        VERBOSE("MinBitRate: %d\n", LE32(buf+9));
+        VERBOSE("MaxBitRate: %d\n", LE32(buf+13));
+        VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17));
+        VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21));
+        VERBOSE("FrameIntervalType: %d\n", buf[25]);
+        int it = buf[25];
+        uint32_t max_fi = 333333; // 30.0fps
+        if (it == 0) {
+            VERBOSE("FrameMinInterval: %d\n", buf[26]);
+            VERBOSE("FrameMaxInterval: %d\n", buf[30]);
+            VERBOSE("FrameIntervalStep: %d\n", buf[34]);
+        } else {
+            int pos = 26;
+            for (int n = 1; n <= it; n++) {
+                uint32_t fi = LE32(buf+pos);
+                if (fi >= max_fi) {
+                    max_fi = fi;
+                }
+                float fps = 1e+7 / fi;
+                VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps);
+                pos += 4;
+            }
+        }
+        if (cfg->payload == PAYLOAD_MJPEG) {
+            if (cfg->width == LE16(buf+5) && cfg->height == LE16(buf+7)) {
+                cfg->FrameIndex = buf[3];
+            }
+            if (cfg->dwFrameInterval == 0) {
+                cfg->dwFrameInterval = max_fi;
+            }
+        }
+    ENDIF
+    IF_EQ_THEN_PRINTF(VS_COLOR_FORMAT, subtype)
+    ENDIF
+}
+
+void _parserConfigurationDescriptor(struct stcamcfg* cfg, uint8_t* buf, int len) {
+    //DBG("buf=%p len=%d\n", buf, len);
+    //DBG_HEX(buf, len);
+    int pos = 0;
+    cfg->_IfClass = 0;
+    cfg->_IfSubClass = 0;
+    while (pos < len) {
+        int type = buf[pos+1];
+        //DBG_BYTES(TYPE_Str(type), buf+pos, buf[pos]);
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CONFIGURATION, type)
+            VERBOSE("NumInterfaces: %d\n", buf[pos+4]);
+        ENDIF
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, type)
+            VERBOSE("FirstInterface: %d\n", buf[pos+2]);
+            VERBOSE("InterfaceCount: %d\n", buf[pos+3]);
+            VERBOSE("FunctionClass: %02X\n", buf[pos+4]);
+            VERBOSE("FunctionSubClass: %02X\n", buf[pos+5]);
+            VERBOSE("FunctionProtocol: %02X\n", buf[pos+6]);
+            VERBOSE("Function: %d\n", buf[pos+7]);
+        ENDIF
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE,type)
+            VERBOSE("InterfaceNumber: %d\n", buf[pos+2]);
+            VERBOSE("AlternateSetting: %d\n", buf[pos+3]);
+            VERBOSE("NumEndpoint: %d\n", buf[pos+4]);
+            VERBOSE("InterfaceClass: %02X\n", buf[pos+5]);
+            VERBOSE("InterfaceSubClass: %02X\n", buf[pos+6]);
+            VERBOSE("InterfaceProtocol: %02X\n", buf[pos+7]);
+            VERBOSE("Interface: %d\n", buf[pos+8]);
+            cfg->_If         = buf[pos+2];
+            cfg->_Ifalt      = buf[pos+3];
+            cfg->_IfClass    = buf[pos+5];
+            cfg->_IfSubClass = buf[pos+6];
+        ENDIF
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_ENDPOINT, type)
+            VERBOSE("EndpointAddress: %02X\n", buf[pos+2]);
+            VERBOSE("Attributes: %02X\n", buf[pos+3]);
+            VERBOSE("MaxPacketSize: %d\n", LE16(buf+pos+4));
+            VERBOSE("Interval: %d\n", buf[pos+6]);
+            if (cfg->_IfClass == CC_VIDEO && cfg->_IfSubClass == SC_VIDEOSTREAMING) {
+                if (cfg->bEndpointAddress == buf[pos+2]) {
+                    if (cfg->wMaxPacketSize == 0) {
+                        cfg->wMaxPacketSize = LE16(buf+pos+4);
+                    }    
+                    if (cfg->wMaxPacketSize == LE16(buf+pos+4)) {
+                        cfg->bInterface = cfg->_If;
+                        cfg->bAlternate = cfg->_Ifalt;
+                    }
+                }
+            }
+        ENDIF
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CS_INTERFACE, type)
+            IF_EQ_THEN_PRINTF(CC_VIDEO, cfg->_IfClass)
+                IF_EQ_THEN_PRINTF(SC_VIDEOCONTROL, cfg->_IfSubClass)
+                    _parserVideoControl(buf+pos, buf[pos]);
+                ENDIF
+                IF_EQ_THEN_PRINTF(SC_VIDEOSTREAMING, cfg->_IfSubClass)
+                    _parserVideoStream(cfg, buf+pos, buf[pos]);
+                ENDIF
+            ENDIF
+            if (cfg->_IfClass == CLASS_AUDIO) {
+                if (cfg->_IfSubClass == 0x01) {
+                    _parserAudioControl(buf+pos, buf[pos]);
+                } else if (cfg->_IfSubClass == 0x02) {
+                    _parserAudioStream(buf+pos, buf[pos]);
+                }
+            }
+        ENDIF
+        IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_HUB, type)
+        ENDIF
+        pos += buf[pos];
+    }
+}
+
+void uvc::_config(struct stcamcfg* cfg)
+{
+    DBG_ASSERT(cfg);
+    int index = 0;
+    uint8_t temp[4];
+    int rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, temp, sizeof(temp));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("Config Descriptor 4bytes", temp, sizeof(temp));
+    DBG_ASSERT(temp[0] == 9);
+    DBG_ASSERT(temp[1] == 0x02);
+    int TotalLength = LE16(temp+2);
+    DBG("TotalLength: %d\n", TotalLength);
+
+    uint8_t* buf = new uint8_t[TotalLength];
+    DBG_ASSERT(buf);
+    rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, 
+             buf, TotalLength);
+    DBG_ASSERT(rc == USBERR_OK);
+
+    _parserConfigurationDescriptor(cfg, buf, TotalLength);
+
+    DBG("cfg->FrameIndex=%d\n", cfg->FrameIndex);
+    DBG("cfg->dwFrameInterval=%u\n", cfg->dwFrameInterval);
+
+    //DBG_ASSERT(cfg->FormatIndex >= 1);
+    //DBG_ASSERT(cfg->FormatIndex <= 2);
+    //DBG_ASSERT(cfg->FrameIndex >= 1);
+    //DBG_ASSERT(cfg->FrameIndex <= 6);
+
+    delete[] buf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvcctl.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,19 @@
+#include "mbed.h"
+#include "uvc.h"
+#define __DEBUG
+#include "mydbg.h"
+
+UsbErr uvc::Control(int req, int cs, int index, uint8_t* buf, int size)
+{
+    UsbErr rc;
+    if (req == SET_CUR) {    
+        rc = m_pDev->controlSend(
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                    req, cs<<8, index, buf, size);
+        return rc;
+    }
+    rc = m_pDev->controlReceive(
+                USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 
+                req, cs<<8, index, buf, size);
+    return rc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvcini.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,263 @@
+#include "mbed.h"
+#include "uvc.h"
+#define __DEBUG
+#include "mydbg.h"
+#include "stcamcfg.h"
+
+const struct stcamcfg stcamcfg_table[] = {
+/*
+{0x045e, 0x074a,
+160,120,
+PAYLOAD_MJPEG,
+0x81, 128,
+1, 5, 2000000, // 160x120 5.0fps
+1, 1, "Microsoft LifeCam VX-700",
+8, 3,
+},*/
+/*
+{0x0c45, 0x62c0,
+160,120,
+PAYLOAD_MJPEG,
+0x81, 128,
+1, 5, 2000000, // 160x120 5.0fps
+1, 1, "UVCA130AF",
+8, 3,
+},*/
+
+{0x046d, 0x0994,
+160,120,
+PAYLOAD_MJPEG,
+0, 0,
+0, 0, 2000000, // 160x120 10.0fps
+0, 0, "Logitech QuickCam Orbit AF",
+0, 3,
+},
+{0x0000, 0x0000,
+160,120,
+PAYLOAD_MJPEG,
+0x00, 0,
+0, 0, 2000000,
+0, 0, "default",
+0, 3,
+},
+};
+
+inline void LE32(uint32_t n, uint8_t* d)
+{
+    d[0] = (uint8_t)n;
+    d[1] = (uint8_t)(n >> 8);
+    d[2] = (uint8_t)(n >> 16);
+    d[3] = (uint8_t)(n >> 24);
+}
+
+void uvc::SetFormatIndex(int index)
+{
+    DBG_ASSERT(index >= 1);
+    DBG_ASSERT(index <= 2);
+    m_FormatIndex = index;
+}
+
+void uvc::SetFrameIndex(int index)
+{
+    DBG_ASSERT(index >= 1);
+    DBG_ASSERT(index <= 8);
+    m_FrameIndex = index;
+}
+
+void uvc::SetFrameInterval(int val)
+{
+    DBG_ASSERT(val >= 333333);
+    DBG_ASSERT(val <= 10000000);
+    m_FrameInterval = val;
+}
+
+void uvc::SetPacketSize(int size)
+{
+    DBG_ASSERT(size >= 128);
+    DBG_ASSERT(size <= 956);
+    m_PacketSize = size;
+}
+
+void uvc::SetImageSize(int width, int height)
+{
+    DBG_ASSERT(width >= 160);
+    DBG_ASSERT(width <= 800);
+    DBG_ASSERT(height >= 120);
+    DBG_ASSERT(height <= 600);
+    m_width = width;
+    m_height = height;
+}
+
+void uvc::SetPayload(int payload)
+{
+    DBG_ASSERT(payload == PAYLOAD_MJPEG || payload == PAYLOAD_YUY2);
+    m_payload = payload;
+}
+
+void uvc::poll()
+{
+    isochronous();
+}
+
+int uvc::_init()
+{
+    m_init = true;
+    UsbErr rc;
+    for(int i = 0; i < 2; i++) {
+        m_pDev = m_pHost->getDeviceByClass(CLASS_VIDEO, m_cam); // UVC
+        if (m_pDev || i > 0) {
+            break;
+        }
+        rc = Usb_poll();
+        if (rc == USBERR_PROCESSING) {
+            VERBOSE("%p USBERR_PROCESSING\n", this);
+            return -1;
+        }
+    }
+    DBG("m_pDev=%p\n", m_pDev);
+    if (!m_pDev) {
+        VERBOSE("%p UVC CAMERA(%d) NOT FOUND\n", this, m_cam);
+        return -1;
+    }
+    DBG_ASSERT(m_pDev);
+    
+    struct stcamcfg cfg;
+    for(int i = 0; ; i++) {
+        cfg = stcamcfg_table[i];
+        if (cfg.idVender == 0x0000) {
+            DBG("not cam config\n");
+            DBG("vid: %04X\n", m_pDev->getVid());
+            DBG("pid: %04X\n", m_pDev->getPid());
+            break;
+        }
+        if (cfg.idVender == m_pDev->getVid() && cfg.idProduct ==  m_pDev->getPid()) {
+            DBG_ASSERT(cfg.name);
+            DBG("found %s\n", cfg.name);
+            break;
+        }
+    }
+
+    if (m_width) {
+        cfg.width = m_width;
+    }
+    if (m_height) {
+        cfg.height = m_height;
+    }
+    if (m_payload != PAYLOAD_UNDEF) {
+        cfg.payload = m_payload;
+    }
+    if (m_FormatIndex) {
+        cfg.FormatIndex = m_FormatIndex;
+    }
+    if (m_FrameIndex) {
+        cfg.FrameIndex = m_FrameIndex;
+    }
+    if (m_FrameInterval) {
+        cfg.dwFrameInterval = m_FrameInterval;
+    }
+    if (m_PacketSize) {
+        cfg.wMaxPacketSize = m_PacketSize;
+    }
+
+    _config(&cfg);
+
+    if (cfg.payload == PAYLOAD_YUY2) {
+        if (cfg.FormatIndex == 0) {
+            VERBOSE("YUY2 FORMAT NOT FOUND\n");
+            return -1;
+        }
+    }
+    
+    if (cfg.iso_FrameCount == 0) {
+        int c = usb_bp_size() / cfg.wMaxPacketSize;
+        if (c > 8) {
+            c = 8;
+        }
+        cfg.iso_FrameCount = c; 
+    }
+    DBG_ASSERT(cfg.iso_FrameCount >= 1);
+    DBG_ASSERT(cfg.iso_FrameCount <= 8);
+    DBG_ASSERT((cfg.iso_FrameCount * cfg.wMaxPacketSize) <= usb_bp_size());
+    if (cfg.iso_itdCount == 0) {
+        cfg.iso_itdCount = 3;
+    }
+    DBG_ASSERT(cfg.iso_itdCount >= 1);
+    DBG("cfg.wMaxPacketSize=%d\n", cfg.wMaxPacketSize);
+    DBG("cfg.iso_FrameCount=%d\n", cfg.iso_FrameCount);
+    DBG("cfg.iso_itdCount=%d\n", cfg.iso_itdCount);
+    DBG_ASSERT(cfg.iso_FrameCount >= 1 && cfg.iso_FrameCount <= 8);
+    //m_pEpIntIn = new UsbEndpoint(m_pDev, 0x83, true, USB_INT, 16);
+    //DBG_ASSERT(m_pEpIntIn);
+    
+    DBG_ASSERT(cfg.bEndpointAddress == 0x81);
+    DBG_ASSERT(cfg.wMaxPacketSize >= 128);
+    DBG_ASSERT(cfg.wMaxPacketSize <= 956);
+    m_PacketSize = cfg.wMaxPacketSize;
+    DBG_ASSERT(m_PacketSize); 
+    m_pEpIsoIn = new UsbEndpoint(m_pDev, cfg.bEndpointAddress, true, USB_ISO, m_PacketSize);
+    DBG_ASSERT(m_pEpIsoIn);
+
+    DBG_ASSERT(cfg.FormatIndex >= 1);
+    DBG_ASSERT(cfg.FormatIndex <= 2);
+    DBG_ASSERT(cfg.FrameIndex >= 1);
+    DBG_ASSERT(cfg.FrameIndex <= 8);
+    DBG_ASSERT(cfg.dwFrameInterval <= 10000000);
+    DBG_ASSERT(cfg.dwFrameInterval >= 333333);
+
+    uint8_t temp1[1];
+    temp1[0] = 0x00;
+    rc = Control(GET_INFO, VS_PROBE_CONTROL, 1, temp1, sizeof(temp1));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_INFO Probe ", temp1, sizeof(temp1));
+
+    uint8_t temp[34];
+    rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, temp, sizeof(temp));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Probe ", temp, sizeof(temp));
+
+    uint8_t param[34];
+    memset(param, 0x00, sizeof(param));
+    param[0] = 0x00;
+    param[2] = cfg.FormatIndex;
+    param[3] = cfg.FrameIndex; // 160x120
+    LE32(cfg.dwFrameInterval, param+4); // Frame Interval
+
+    DBG_BYTES("SET_CUR Probe ", param, sizeof(param));
+    rc = Control(SET_CUR, VS_PROBE_CONTROL, 1, param, sizeof(param));
+    DBG_ASSERT(rc == USBERR_OK);
+
+    rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, temp, sizeof(temp));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Probe ", temp, sizeof(temp));
+
+    rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, temp, sizeof(temp));
+    DBG_ASSERT(rc == USBERR_OK);
+    DBG_BYTES("GET_CUR Commit", temp, sizeof(temp));
+
+    DBG_BYTES("SET_CUR Commit", param, sizeof(param));
+    rc = Control(SET_CUR, VS_COMMIT_CONTROL, 1, param, sizeof(param));
+    DBG_ASSERT(rc == USBERR_OK);
+
+    //USBH_SET_INTERFACE(1, 1); // alt=1 size=128
+    DBG_ASSERT(cfg.bInterface >= 1); 
+    DBG_ASSERT(cfg.bAlternate >= 1);
+    DBG_ASSERT(cfg.bAlternate <= 6);
+    //rc = m_pDev->controlSend(
+    //              USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, 
+    //              SET_INTERFACE, cfg.bAlternate, cfg.bInterface, NULL, 0);
+    rc = m_pDev->SetInterfaceAlternate(cfg.bInterface, cfg.bAlternate);
+    DBG_ASSERT(rc == USBERR_OK);
+
+    DBG_ASSERT(cfg.iso_FrameCount >= 1);
+    DBG_ASSERT(cfg.iso_FrameCount <= 8);
+    m_FrameCount = cfg.iso_FrameCount;
+    DBG_ASSERT(cfg.iso_itdCount >= 1);
+    DBG_ASSERT(cfg.iso_itdCount <= 8);
+    m_itdCount = cfg.iso_itdCount;
+    
+    LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable
+    LPC_USB->HcControl |= OR_CONTROL_IE;  // IsochronousEnable
+
+    m_connect = true;
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uvc/uvcsub.cpp	Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,21 @@
+#include "mbed.h"
+#include "uvc.h"
+
+void uvc::wait(float s)
+{
+    Timer t;
+    t.start();
+    while(t.read() < s) {
+        poll();
+    }
+}
+
+void uvc::wait_ms(int ms)
+{
+    Timer t;
+    t.start();
+    while(t.read_ms() < ms) {
+        poll();
+    }
+}
+