BTstack Bluetooth stack

Dependencies:   mbed USBHost

USBホストライブラリを変更しました。

  • Bluetoothマウス(VGP-BMS33)での動作を確認しました。mouse_demo.cpp

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Jun 26 14:27:45 2012 +0000
Child:
1:b657594559be
Commit message:
fix overflow spp_service_buffer

Changed in this revision

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/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/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.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/sdp.c Show annotated file Show diff for this revision Revisions of this file
BTstack/sdp.h Show annotated file Show diff for this revision Revisions of this file
BTstack/sdp_util.c 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
led_counter.cpp 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
mouse_demo.cpp 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
spp_counter.cpp Show annotated file Show diff for this revision Revisions of this file
spp_demo.cpp Show annotated file Show diff for this revision Revisions of this file
spp_flowcontrol.cpp 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/BTstack/bt_control.h	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,24 @@
+#define EMBEDDED
+#define HAVE_TICK
+
+//#define HAVE_INIT_SCRIPT
+//#define HAVE_BZERO
+//#define HAVE_EHCILL
+
+#define ENABLE_LOG_INFO 
+#define ENABLE_LOG_ERROR
+
+#define HCI_ACL_PAYLOAD_SIZE 52
+
+#define HAVE_MALLOC
+
+//#define MAX_SPP_CONNECTIONS 1
+//#define MAX_NO_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
+//#define MAX_NO_L2CAP_SERVICES  2
+//#define MAX_NO_L2CAP_CHANNELS  (1+MAX_SPP_CONNECTIONS)
+//#define MAX_NO_RFCOMM_MULTIPLEXERS MAX_SPP_CONNECTIONS
+//#define MAX_NO_RFCOMM_SERVICES 1
+//#define MAX_NO_RFCOMM_CHANNELS MAX_SPP_CONNECTIONS
+//#define MAX_NO_DB_MEM_DEVICE_LINK_KEYS  2
+//#define MAX_NO_DB_MEM_DEVICE_NAMES 0
+//#define MAX_NO_DB_MEM_SERVICES 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/debug.h	Tue Jun 26 14:27:45 2012 +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/hal_mbed/hal_cpu.cpp	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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.25);
+}
+
+int  hal_tick_get_tick_period_in_ms(void){
+    return 250;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci.c	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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/remote_device_db.h	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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.c	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,1869 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  rfcomm.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // memcpy
+#include <stdint.h>
+
+#include <btstack/btstack.h>
+#include <btstack/hci_cmds.h>
+#include <btstack/utils.h>
+
+#include <btstack/utils.h>
+#include "btstack_memory.h"
+#include "hci.h"
+#include "hci_dump.h"
+#include "debug.h"
+#include "rfcomm.h"
+
+// workaround for missing PRIxPTR on mspgcc (16/20-bit MCU)
+#ifndef PRIxPTR
+#if defined(__MSP430X__)  &&  defined(__MSP430X_LARGE__)
+#define PRIxPTR "lx"
+#else
+#define PRIxPTR "x"
+#endif
+#endif
+
+
+// Control field values      bit no.       1 2 3 4 PF 6 7 8
+#define BT_RFCOMM_SABM       0x3F       // 1 1 1 1  1 1 0 0
+#define BT_RFCOMM_UA         0x73       // 1 1 0 0  1 1 1 0
+#define BT_RFCOMM_DM         0x0F       // 1 1 1 1  0 0 0 0
+#define BT_RFCOMM_DM_PF      0x1F        // 1 1 1 1  1 0 0 0
+#define BT_RFCOMM_DISC       0x53       // 1 1 0 0  1 0 1 0
+#define BT_RFCOMM_UIH        0xEF       // 1 1 1 1  0 1 1 1
+#define BT_RFCOMM_UIH_PF     0xFF       // 1 1 1 1  0 1 1 1
+
+// Multiplexer message types 
+#define BT_RFCOMM_CLD_CMD    0xC3
+#define BT_RFCOMM_FCON_CMD   0xA3
+#define BT_RFCOMM_FCON_RSP   0xA1
+#define BT_RFCOMM_FCOFF_CMD  0x63
+#define BT_RFCOMM_FCOFF_RSP  0x61
+#define BT_RFCOMM_MSC_CMD    0xE3
+#define BT_RFCOMM_MSC_RSP    0xE1
+#define BT_RFCOMM_NSC_RSP    0x11
+#define BT_RFCOMM_PN_CMD     0x83
+#define BT_RFCOMM_PN_RSP     0x81
+#define BT_RFCOMM_RLS_CMD    0x53
+#define BT_RFCOMM_RLS_RSP    0x51
+#define BT_RFCOMM_RPN_CMD    0x93
+#define BT_RFCOMM_RPN_RSP    0x91
+#define BT_RFCOMM_TEST_CMD   0x23
+#define BT_RFCOMM_TEST_RSP   0x21
+
+#define RFCOMM_MULIPLEXER_TIMEOUT_MS 60000
+
+// FCS calc 
+#define BT_RFCOMM_CODE_WORD         0xE0 // pol = x8+x2+x1+1
+#define BT_RFCOMM_CRC_CHECK_LEN     3
+#define BT_RFCOMM_UIHCRC_CHECK_LEN  2
+
+#include "l2cap.h"
+
+// used for debugging
+// #define RFCOMM_LOG_CREDITS
+
+// global rfcomm data
+static uint16_t      rfcomm_client_cid_generator;  // used for client channel IDs
+
+// linked lists for all
+static linked_list_t rfcomm_multiplexers = NULL;
+static linked_list_t rfcomm_channels = NULL;
+static linked_list_t rfcomm_services = NULL;
+
+static void (*app_packet_handler)(void * connection, uint8_t packet_type,
+                                  uint16_t channel, uint8_t *packet, uint16_t size);
+
+static void rfcomm_run(void);
+static void rfcomm_hand_out_credits(void);
+static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event);
+static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event);
+static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel);
+static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event);
+
+
+// MARK: RFCOMM CLIENT EVENTS
+
+// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+static void rfcomm_emit_connection_request(rfcomm_channel_t *channel) {
+    uint8_t event[11];
+    event[0] = RFCOMM_EVENT_INCOMING_CONNECTION;
+    event[1] = sizeof(event) - 2;
+    bt_flip_addr(&event[2], channel->multiplexer->remote_addr);
+    event[8] = channel->dlci >> 1;
+    bt_store_16(event, 9, channel->rfcomm_cid);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+// API Change: BTstack-0.3.50x uses
+// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
+// next Cydia release will use SVN version of this
+// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
+static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status) {
+    uint8_t event[16];
+    uint8_t pos = 0;
+    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
+    event[pos++] = sizeof(event) - 2;
+    event[pos++] = status;
+    bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
+    bt_store_16(event,  pos, channel->multiplexer->con_handle);   pos += 2;
+    event[pos++] = channel->dlci >> 1;
+    bt_store_16(event, pos, channel->rfcomm_cid); pos += 2;       // channel ID
+    bt_store_16(event, pos, channel->max_frame_size); pos += 2;   // max frame size
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
+}
+
+static void rfcomm_emit_channel_open_failed_outgoing_memory(void * connection, bd_addr_t *addr, uint8_t server_channel){
+    uint8_t event[16];
+    uint8_t pos = 0;
+    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
+    event[pos++] = sizeof(event) - 2;
+    event[pos++] = BTSTACK_MEMORY_ALLOC_FAILED;
+    bt_flip_addr(&event[pos], *addr); pos += 6;
+    bt_store_16(event,  pos, 0);   pos += 2;
+    event[pos++] = server_channel;
+    bt_store_16(event, pos, 0); pos += 2;   // channel ID
+    bt_store_16(event, pos, 0); pos += 2;   // max frame size
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
+}
+
+// data: event(8), len(8), creidts incoming(8), new credits incoming(8), credits outgoing(8)
+static inline void rfcomm_emit_credit_status(rfcomm_channel_t * channel) {
+#ifdef RFCOMM_LOG_CREDITS
+    uint8_t event[5];
+    event[0] = 0x88;
+    event[1] = sizeof(event) - 2;
+    event[2] = channel->credits_incoming;
+    event[3] = channel->new_credits_incoming;
+    event[4] = channel->credits_outgoing;
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+#endif
+}
+
+// data: event(8), len(8), rfcomm_cid(16)
+static void rfcomm_emit_channel_closed(rfcomm_channel_t * channel) {
+    uint8_t event[4];
+    event[0] = RFCOMM_EVENT_CHANNEL_CLOSED;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->rfcomm_cid);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+static void rfcomm_emit_credits(rfcomm_channel_t * channel, uint8_t credits) {
+    uint8_t event[5];
+    event[0] = RFCOMM_EVENT_CREDITS;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->rfcomm_cid);
+    event[4] = credits;
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
+    uint8_t event[4];
+    event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    event[3] = channel;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+// MARK: RFCOMM MULTIPLEXER HELPER
+
+static uint16_t rfcomm_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
+
+    // Assume RFCOMM header with credits and single byte length field
+    uint16_t max_frame_size = l2cap_mtu - 5;
+    
+    // single byte can denote len up to 127
+    if (max_frame_size > 127) {
+        max_frame_size--;
+    }
+
+    log_info("rfcomm_max_frame_size_for_l2cap_mtu:  %u -> %u\n", l2cap_mtu, max_frame_size);
+    return max_frame_size;
+}
+
+static void rfcomm_multiplexer_initialize(rfcomm_multiplexer_t *multiplexer){
+
+    memset(multiplexer, 0, sizeof(rfcomm_multiplexer_t));
+
+    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
+    multiplexer->l2cap_credits = 0;
+    multiplexer->send_dm_for_dlci = 0;
+    multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_create_for_addr(bd_addr_t *addr){
+    
+    // alloc structure 
+    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t*)btstack_memory_rfcomm_multiplexer_get();
+    if (!multiplexer) return NULL;
+    
+    // fill in 
+    rfcomm_multiplexer_initialize(multiplexer);
+    BD_ADDR_COPY(&multiplexer->remote_addr, addr);
+
+    // add to services list
+    linked_list_add(&rfcomm_multiplexers, (linked_item_t *) multiplexer);
+    
+    return multiplexer;
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_for_addr(bd_addr_t *addr){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        if (BD_ADDR_CMP(addr, multiplexer->remote_addr) == 0) {
+            return multiplexer;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_for_l2cap_cid(uint16_t l2cap_cid) {
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        if (multiplexer->l2cap_cid == l2cap_cid) {
+            return multiplexer;
+        };
+    }
+    return NULL;
+}
+
+static int rfcomm_multiplexer_has_channels(rfcomm_multiplexer_t * multiplexer){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->multiplexer == multiplexer) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+// MARK: RFCOMM CHANNEL HELPER
+
+static void rfcomm_dump_channels(void){
+#ifndef EMBEDDED
+    linked_item_t * it;
+    int channels = 0;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
+        log_info("Channel #%u: addr %p, state %u\n", channels, channel, channel->state);
+        channels++;
+    }
+#endif
+}
+
+static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer, 
+                               rfcomm_service_t *service, uint8_t server_channel){
+    
+    // don't use 0 as channel id
+    if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
+    
+    // setup channel
+    memset(channel, 0, sizeof(rfcomm_channel_t));
+    
+    channel->state             = RFCOMM_CHANNEL_CLOSED;
+    channel->state_var         = RFCOMM_CHANNEL_STATE_VAR_NONE;
+    
+    channel->multiplexer      = multiplexer;
+    channel->service          = service;
+    channel->rfcomm_cid       = rfcomm_client_cid_generator++;
+    channel->max_frame_size   = multiplexer->max_frame_size;
+
+    channel->credits_incoming = 0;
+    channel->credits_outgoing = 0;
+    channel->packets_granted  = 0;
+
+    // incoming flow control not active
+    channel->new_credits_incoming  = 0x30;
+    channel->incoming_flow_control = 0;
+    
+    if (service) {
+        // incoming connection
+        channel->outgoing = 0;
+        channel->dlci = (server_channel << 1) |  multiplexer->outgoing;
+        if (channel->max_frame_size > service->max_frame_size) {
+            channel->max_frame_size = service->max_frame_size;
+        }
+        channel->incoming_flow_control = service->incoming_flow_control;
+        channel->new_credits_incoming  = service->incoming_initial_credits;
+    } else {
+        // outgoing connection
+        channel->outgoing = 1;
+        channel->dlci = (server_channel << 1) | (multiplexer->outgoing ^ 1);
+    }
+}
+
+// service == NULL -> outgoing channel
+static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
+                                                rfcomm_service_t * service, uint8_t server_channel){
+
+    log_info("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
+    rfcomm_dump_channels();
+
+    // alloc structure 
+    rfcomm_channel_t * channel = (rfcomm_channel_t*)btstack_memory_rfcomm_channel_get();
+    if (!channel) return NULL;
+    
+    // fill in 
+    rfcomm_channel_initialize(channel, multiplexer, service, server_channel);
+    
+    // add to services list
+    linked_list_add(&rfcomm_channels, (linked_item_t *) channel);
+    
+    return channel;
+}
+
+static rfcomm_channel_t * rfcomm_channel_for_rfcomm_cid(uint16_t rfcomm_cid){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->rfcomm_cid == rfcomm_cid) {
+            return channel;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multiplexer_t * multiplexer, uint8_t dlci){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->dlci == dlci && channel->multiplexer == multiplexer) {
+            return channel;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_service_t * rfcomm_service_for_channel(uint8_t server_channel){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
+        rfcomm_service_t * service = ((rfcomm_service_t *) it);
+        if ( service->server_channel == server_channel){
+            return service;
+        };
+    }
+    return NULL;
+}
+
+// MARK: RFCOMM SEND
+
+/**
+ * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
+ */
+static int rfcomm_send_packet_for_multiplexer(rfcomm_multiplexer_t *multiplexer, uint8_t address, uint8_t control, uint8_t credits, uint8_t *data, uint16_t len){
+
+    if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) return BTSTACK_ACL_BUFFERS_FULL;
+    
+    uint8_t * rfcomm_out_buffer = l2cap_get_outgoing_buffer();
+    
+    uint16_t pos = 0;
+    uint8_t crc_fields = 3;
+    
+    rfcomm_out_buffer[pos++] = address;
+    rfcomm_out_buffer[pos++] = control;
+    
+    // length field can be 1 or 2 octets
+    if (len < 128){
+        rfcomm_out_buffer[pos++] = (len << 1)| 1;     // bits 0-6
+    } else {
+        rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
+        rfcomm_out_buffer[pos++] = len >> 7;          // bits 7-14
+        crc_fields++;
+    }
+
+    // add credits for UIH frames when PF bit is set
+    if (control == BT_RFCOMM_UIH_PF){
+        rfcomm_out_buffer[pos++] = credits;
+    }
+    
+    // copy actual data
+    if (len) {
+        memcpy(&rfcomm_out_buffer[pos], data, len);
+        pos += len;
+    }
+    
+    // UIH frames only calc FCS over address + control (5.1.1)
+    if ((control & 0xef) == BT_RFCOMM_UIH){
+        crc_fields = 2;
+    }
+    rfcomm_out_buffer[pos++] =  crc8_calc(rfcomm_out_buffer, crc_fields); // calc fcs
+
+    int credits_taken = 0;
+    if (multiplexer->l2cap_credits){
+        credits_taken++;
+        multiplexer->l2cap_credits--;
+    } else {
+        log_info( "rfcomm_send_packet addr %02x, ctrl %02x size %u without l2cap credits\n", address, control, pos);
+    }
+    
+    int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
+    
+    if (err) {
+        // undo credit counting
+        multiplexer->l2cap_credits += credits_taken;
+    }
+    return err;
+}
+
+// C/R Flag in Address
+// - terms: initiator = station that creates multiplexer with SABM
+// - terms: responder = station that responds to multiplexer setup with UA
+// "For SABM, UA, DM and DISC frames C/R bit is set according to Table 1 in GSM 07.10, section 5.2.1.2"
+//    - command initiator = 1 /response responder = 1
+//    - command responder = 0 /response initiator = 0
+// "For UIH frames, the C/R bit is always set according to section 5.4.3.1 in GSM 07.10. 
+//  This applies independently of what is contained wthin the UIH frames, either data or control messages."
+//    - c/r = 1 for frames by initiating station, 0 = for frames by responding station
+
+// C/R Flag in Message
+// "In the message level, the C/R bit in the command type field is set as stated in section 5.4.6.2 in GSM 07.10." 
+//   - If the C/R bit is set to 1 the message is a command
+//   - if it is set to 0 the message is a response.
+
+// temp/old messge construction
+
+// new object oriented version
+static int rfcomm_send_sabm(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);   // command
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_SABM, 0, NULL, 0);
+}
+
+static int rfcomm_send_disc(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);  // command
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DISC, 0, NULL, 0);
+}
+
+static int rfcomm_send_ua(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UA, 0, NULL, 0);
+}
+
+static int rfcomm_send_dm_pf(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DM_PF, 0, NULL, 0);
+}
+
+static int rfcomm_send_uih_msc_cmd(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
+    uint8_t payload[4]; 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_MSC_CMD;
+    payload[pos++] = 2 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = signals;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_msc_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
+    uint8_t address = (1 << 0) | (multiplexer->outgoing<< 1);
+    uint8_t payload[4]; 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_MSC_RSP;
+    payload[pos++] = 2 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = signals;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_pn_command(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint16_t max_frame_size){
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_PN_CMD;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = dlci;
+    payload[pos++] = 0xf0; // pre-defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
+    payload[pos++] = 0; // priority
+    payload[pos++] = 0; // max 60 seconds ack
+    payload[pos++] = max_frame_size & 0xff; // max framesize low
+    payload[pos++] = max_frame_size >> 8;   // max framesize high
+    payload[pos++] = 0x00; // number of retransmissions
+    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+// "The response may not change the DLCI, the priority, the convergence layer, or the timer value." RFCOMM-tutorial.pdf
+static int rfcomm_send_uih_pn_response(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,
+                                       uint8_t priority, uint16_t max_frame_size){
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_PN_RSP;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = dlci;
+    payload[pos++] = 0xe0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
+    payload[pos++] = priority; // priority
+    payload[pos++] = 0; // max 60 seconds ack
+    payload[pos++] = max_frame_size & 0xff; // max framesize low
+    payload[pos++] = max_frame_size >> 8;   // max framesize high
+    payload[pos++] = 0x00; // number of retransmissions
+    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_rpn_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, rfcomm_rpn_data_t *rpn_data) {
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_RPN_RSP;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = rpn_data->baud_rate;
+    payload[pos++] = rpn_data->flags;
+    payload[pos++] = rpn_data->flow_control;
+    payload[pos++] = rpn_data->xon;
+    payload[pos++] = rpn_data->xoff;
+    payload[pos++] = rpn_data->parameter_mask_0;
+    payload[pos++] = rpn_data->parameter_mask_1;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_data(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t *data, uint16_t len){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2); 
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, data, len);
+}
+
+static void rfcomm_send_uih_credits(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,  uint8_t credits){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) |  (dlci << 2); 
+    rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH_PF, credits, NULL, 0);
+}
+
+// MARK: RFCOMM MULTIPLEXER
+
+static void rfcomm_multiplexer_finalize(rfcomm_multiplexer_t * multiplexer){
+    
+    // remove (potential) timer
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    
+    // close and remove all channels
+    linked_item_t *it = (linked_item_t *) &rfcomm_channels;
+    while (it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it->next;
+        if (channel->multiplexer == multiplexer) {
+            // emit appropriate events
+            if (channel->state == RFCOMM_CHANNEL_OPEN) {
+                rfcomm_emit_channel_closed(channel);
+            } else {
+                rfcomm_emit_channel_opened(channel, RFCOMM_MULTIPLEXER_STOPPED); 
+            }
+            // remove from list
+            it->next = it->next->next;
+            // free channel struct
+            btstack_memory_rfcomm_channel_free(channel);
+        } else {
+            it = it->next;
+        }
+    }
+    
+    // keep reference to l2cap channel
+    uint16_t l2cap_cid = multiplexer->l2cap_cid;
+    
+    // remove mutliplexer
+    linked_list_remove( &rfcomm_multiplexers, (linked_item_t *) multiplexer);
+    btstack_memory_rfcomm_multiplexer_free(multiplexer);
+    
+    // close l2cap multiplexer channel, too
+    l2cap_disconnect_internal(l2cap_cid, 0x13);
+}
+
+static void rfcomm_multiplexer_timer_handler(timer_source_t *timer){
+    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t *) linked_item_get_user( (linked_item_t *) timer);
+    if (!rfcomm_multiplexer_has_channels(multiplexer)){
+        log_info( "rfcomm_multiplexer_timer_handler timeout: shutting down multiplexer!\n");
+        rfcomm_multiplexer_finalize(multiplexer);
+    }
+}
+
+static void rfcomm_multiplexer_prepare_idle_timer(rfcomm_multiplexer_t * multiplexer){
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    if (!rfcomm_multiplexer_has_channels(multiplexer)){
+        // start timer for multiplexer timeout check
+        run_loop_set_timer(&multiplexer->timer, RFCOMM_MULIPLEXER_TIMEOUT_MS);
+        multiplexer->timer.process = rfcomm_multiplexer_timer_handler;
+        linked_item_set_user((linked_item_t*) &multiplexer->timer, multiplexer);
+        run_loop_add_timer(&multiplexer->timer);
+        multiplexer->timer_active = 1;
+    }
+}
+
+static void rfcomm_multiplexer_opened(rfcomm_multiplexer_t *multiplexer){
+    log_info("Multiplexer up and running\n");
+    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
+    
+    rfcomm_channel_event_t event = { CH_EVT_MULTIPLEXER_READY };
+    
+    // transition of channels that wait for multiplexer 
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->multiplexer != multiplexer) continue;
+        rfcomm_channel_state_machine(channel, &event);
+    }        
+    
+    rfcomm_run();
+    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
+}
+
+
+/**
+ * @return handled packet
+ */
+static int rfcomm_multiplexer_hci_event_handler(uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    uint16_t  psm;
+    uint16_t l2cap_cid;
+    hci_con_handle_t con_handle;
+    rfcomm_multiplexer_t *multiplexer = NULL;
+    switch (packet[0]) {
+            
+        // accept incoming PSM_RFCOMM connection if no multiplexer exists yet
+        case L2CAP_EVENT_INCOMING_CONNECTION:
+            // data: event(8), len(8), address(48), handle (16),  psm (16), source cid(16) dest cid(16)
+            bt_flip_addr(event_addr, &packet[2]);
+            con_handle = READ_BT_16(packet,  8);
+            psm        = READ_BT_16(packet, 10); 
+            l2cap_cid  = READ_BT_16(packet, 12); 
+
+            if (psm != PSM_RFCOMM) break;
+
+            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
+            
+            if (multiplexer) {
+                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - multiplexer already exists", l2cap_cid);
+                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
+                return 1;
+            }
+            
+            // create and inititialize new multiplexer instance (incoming)
+            multiplexer = rfcomm_multiplexer_create_for_addr(&event_addr);
+            if (!multiplexer){
+                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - no memory left", l2cap_cid);
+                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
+                return 1;
+            }
+            
+            multiplexer->con_handle = con_handle;
+            multiplexer->l2cap_cid = l2cap_cid;
+            multiplexer->state = RFCOMM_MULTIPLEXER_W4_SABM_0;
+            
+            log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => accept", l2cap_cid);
+            l2cap_accept_connection_internal(l2cap_cid);
+            return 1;
+            
+        // l2cap connection opened -> store l2cap_cid, remote_addr
+        case L2CAP_EVENT_CHANNEL_OPENED: 
+            if (READ_BT_16(packet, 11) != PSM_RFCOMM) break;
+            log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_RFCOMM\n");
+            // get multiplexer for remote addr
+            con_handle = READ_BT_16(packet, 9);
+            l2cap_cid = READ_BT_16(packet, 13);
+            bt_flip_addr(event_addr, &packet[3]);
+            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
+            if (!multiplexer) {
+                log_error("L2CAP_EVENT_CHANNEL_OPENED but no multiplexer prepared\n");
+                return 1;
+            }
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_CONNECT) {
+                log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection\n");
+                // wrong remote addr
+                if (BD_ADDR_CMP(event_addr, multiplexer->remote_addr)) break;
+                multiplexer->l2cap_cid = l2cap_cid;
+                multiplexer->con_handle = con_handle;
+                // send SABM #0
+                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_SABM_0;
+            } else { // multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0
+                
+                // set max frame size based on l2cap MTU
+                multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
+            }
+            return 1;
+            
+            // l2cap disconnect -> state = RFCOMM_MULTIPLEXER_CLOSED;
+            
+        case L2CAP_EVENT_CREDITS:
+            // data: event(8), len(8), local_cid(16), credits(8)
+            l2cap_cid = READ_BT_16(packet, 2);
+            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
+            if (!multiplexer) break;
+            multiplexer->l2cap_credits += packet[4];
+            
+            // log_info("L2CAP_EVENT_CREDITS: %u (now %u)\n", packet[4], multiplexer->l2cap_credits);
+
+            // new credits, continue with signaling
+            rfcomm_run();
+            
+            if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) break;
+            rfcomm_hand_out_credits();
+            return 1;
+        
+        case DAEMON_EVENT_HCI_PACKET_SENT:
+            // testing DMA done code
+            rfcomm_run();
+            break;
+            
+        case L2CAP_EVENT_CHANNEL_CLOSED:
+            // data: event (8), len(8), channel (16)
+            l2cap_cid = READ_BT_16(packet, 2);
+            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
+            if (!multiplexer) break;
+            switch (multiplexer->state) {
+                case RFCOMM_MULTIPLEXER_W4_SABM_0:
+                case RFCOMM_MULTIPLEXER_W4_UA_0:
+                case RFCOMM_MULTIPLEXER_OPEN:
+                    rfcomm_multiplexer_finalize(multiplexer);
+                    return 1;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static int rfcomm_multiplexer_l2cap_packet_handler(uint16_t channel, uint8_t *packet, uint16_t size){
+    
+    // get or create a multiplexer for a certain device
+    rfcomm_multiplexer_t *multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
+    if (!multiplexer) return 0;
+    
+    // but only care for multiplexer control channel
+    uint8_t frame_dlci = packet[0] >> 2;
+    if (frame_dlci) return 0;
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+    switch (packet[1]){
+            
+        case BT_RFCOMM_SABM:
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0){
+                log_info("Received SABM #0\n");
+                multiplexer->outgoing = 0;
+                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0;
+                return 1;
+            }
+            break;
+            
+        case BT_RFCOMM_UA:
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_UA_0) {
+                // UA #0 -> send UA #0, state = RFCOMM_MULTIPLEXER_OPEN
+                log_info("Received UA #0 \n");
+                rfcomm_multiplexer_opened(multiplexer);
+                return 1;
+            }
+            break;
+            
+        case BT_RFCOMM_DISC:
+            // DISC #0 -> send UA #0, close multiplexer
+            log_info("Received DISC #0, (ougoing = %u)\n", multiplexer->outgoing);
+            multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC;
+            return 1;
+            
+        case BT_RFCOMM_DM:
+            // DM #0 - we shouldn't get this, just give up
+            log_info("Received DM #0\n");
+            log_info("-> Closing down multiplexer\n");
+            rfcomm_multiplexer_finalize(multiplexer);
+            return 1;
+            
+        case BT_RFCOMM_UIH:
+            if (packet[payload_offset] == BT_RFCOMM_CLD_CMD){
+                // Multiplexer close down (CLD) -> close mutliplexer
+                log_info("Received Multiplexer close down command\n");
+                log_info("-> Closing down multiplexer\n");
+                rfcomm_multiplexer_finalize(multiplexer);
+                return 1;
+            }
+            break;
+            
+        default:
+            break;
+            
+    }
+    return 0;
+}
+
+static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event){
+    
+    // process stored DM responses
+    if (multiplexer->send_dm_for_dlci){
+        rfcomm_send_dm_pf(multiplexer, multiplexer->send_dm_for_dlci);
+        multiplexer->send_dm_for_dlci = 0;
+    }
+
+    switch (multiplexer->state) {
+        case RFCOMM_MULTIPLEXER_SEND_SABM_0:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending SABM #0 - (multi 0x%p)\n", multiplexer);
+                    multiplexer->state = RFCOMM_MULTIPLEXER_W4_UA_0;
+                    rfcomm_send_sabm(multiplexer, 0);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case RFCOMM_MULTIPLEXER_SEND_UA_0:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending UA #0\n");
+                    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
+                    rfcomm_send_ua(multiplexer, 0);
+                    rfcomm_multiplexer_opened(multiplexer);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending UA #0\n");
+                    log_info("Closing down multiplexer\n");
+                    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
+                    rfcomm_send_ua(multiplexer, 0);
+                    rfcomm_multiplexer_finalize(multiplexer);
+                    // try to detect authentication errors: drop link key if multiplexer closed before first channel got opened
+                    if (!multiplexer->at_least_one_connection){
+                        log_info("TODO: no connections established - delete link key prophylactically\n");
+                        // hci_send_cmd(&hci_delete_stored_link_key, multiplexer->remote_addr);
+                    }
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+// MARK: RFCOMM CHANNEL
+
+static void rfcomm_hand_out_credits(void){
+    linked_item_t * it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
+        if (channel->state != RFCOMM_CHANNEL_OPEN) {
+            // log_info("RFCOMM_EVENT_CREDITS: multiplexer not open\n");
+            continue;
+        }
+        if (channel->packets_granted) {
+            // log_info("RFCOMM_EVENT_CREDITS: already packets granted\n");
+            continue;
+        }
+        if (!channel->credits_outgoing) {
+            // log_info("RFCOMM_EVENT_CREDITS: no outgoing credits\n");
+            continue;
+        }
+        if (!channel->multiplexer->l2cap_credits){
+            // log_info("RFCOMM_EVENT_CREDITS: no l2cap credits\n");
+            continue;
+        }
+        // channel open, multiplexer has l2cap credits and we didn't hand out credit before -> go!
+        // log_info("RFCOMM_EVENT_CREDITS: 1\n");
+        channel->packets_granted += 1;
+        rfcomm_emit_credits(channel, 1);
+    }        
+}
+
+static void rfcomm_channel_send_credits(rfcomm_channel_t *channel, uint8_t credits){
+    rfcomm_send_uih_credits(channel->multiplexer, channel->dlci, credits);
+    channel->credits_incoming += credits;
+    
+    rfcomm_emit_credit_status(channel);
+}
+
+static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
+    
+    log_info("rfcomm_channel_opened!\n");
+    
+    rfChannel->state = RFCOMM_CHANNEL_OPEN;
+    rfcomm_emit_channel_opened(rfChannel, 0);
+    rfcomm_hand_out_credits();
+
+    // remove (potential) timer
+    rfcomm_multiplexer_t *multiplexer = rfChannel->multiplexer;
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    // hack for problem detecting authentication failure
+    multiplexer->at_least_one_connection = 1;
+    
+    // start next connection request if pending
+    rfcomm_run();
+}
+
+static void rfcomm_channel_packet_handler_uih(rfcomm_multiplexer_t *multiplexer, uint8_t * packet, uint16_t size){
+    const uint8_t frame_dlci = packet[0] >> 2;
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+
+    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, frame_dlci);
+    if (!channel) return;
+    
+    // handle new outgoing credits
+    if (packet[1] == BT_RFCOMM_UIH_PF) {
+        
+        // add them
+        uint16_t new_credits = packet[3+length_offset];
+        channel->credits_outgoing += new_credits;
+        log_info( "RFCOMM data UIH_PF, new credits: %u, now %u\n", new_credits, channel->credits_outgoing);
+
+        // notify channel statemachine 
+        rfcomm_channel_event_t channel_event = { CH_EVT_RCVD_CREDITS };
+        rfcomm_channel_state_machine(channel, &channel_event);
+    }
+    
+    // contains payload?
+    if (size - 1 > payload_offset){
+
+        // log_info( "RFCOMM data UIH_PF, size %u, channel %p\n", size-payload_offset-1, rfChannel->connection);
+
+        // decrease incoming credit counter
+        if (channel->credits_incoming > 0){
+            channel->credits_incoming--;
+        }
+        
+        // deliver payload
+        (*app_packet_handler)(channel->connection, RFCOMM_DATA_PACKET, channel->rfcomm_cid,
+                              &packet[payload_offset], size-payload_offset-1);
+    }
+    
+    // automatically provide new credits to remote device, if no incoming flow control
+    if (!channel->incoming_flow_control && channel->credits_incoming < 5){
+        channel->new_credits_incoming = 0x30;
+    }    
+    
+    rfcomm_emit_credit_status(channel);
+    
+    // we received new RFCOMM credits, hand them out if possible
+    rfcomm_hand_out_credits();
+}
+
+static void rfcomm_channel_accept_pn(rfcomm_channel_t *channel, rfcomm_channel_event_pn_t *event){
+    // priority of client request
+    channel->pn_priority = event->priority;
+    
+    // new credits
+    channel->credits_outgoing = event->credits_outgoing;
+    
+    // negotiate max frame size
+    if (channel->max_frame_size > channel->multiplexer->max_frame_size) {
+        channel->max_frame_size = channel->multiplexer->max_frame_size;
+    }
+    if (channel->max_frame_size > event->max_frame_size) {
+        channel->max_frame_size = event->max_frame_size;
+    }
+    
+}
+
+static void rfcomm_channel_finalize(rfcomm_channel_t *channel){
+
+    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
+
+    // remove from list
+    linked_list_remove( &rfcomm_channels, (linked_item_t *) channel);
+
+    // free channel
+    btstack_memory_rfcomm_channel_free(channel);
+    
+    // update multiplexer timeout after channel was removed from list
+    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
+}
+
+static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event){
+
+    // TODO: if client max frame size is smaller than RFCOMM_DEFAULT_SIZE, send PN
+
+    
+    // lookup existing channel
+    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, dlci);
+
+    // log_info("rfcomm_channel_state_machine_2 lookup dlci #%u = 0x%08x - event %u\n", dlci, (int) channel, event->type);
+
+    if (channel) {
+        rfcomm_channel_state_machine(channel, event);
+        return;
+    }
+    
+    // service registered?
+    rfcomm_service_t * service = rfcomm_service_for_channel(dlci >> 1);
+    // log_info("rfcomm_channel_state_machine_2 service dlci #%u = 0x%08x\n", dlci, (int) service);
+    if (!service) {
+        // discard request by sending disconnected mode
+        multiplexer->send_dm_for_dlci = dlci;
+        return;
+    }
+
+    // create channel for some events
+    switch (event->type) {
+        case CH_EVT_RCVD_SABM:
+        case CH_EVT_RCVD_PN:
+        case CH_EVT_RCVD_RPN_REQ:
+        case CH_EVT_RCVD_RPN_CMD:
+            // setup incoming channel
+            channel = rfcomm_channel_create(multiplexer, service, dlci >> 1);
+            if (!channel){
+                // discard request by sending disconnected mode
+                multiplexer->send_dm_for_dlci = dlci;
+            }
+            break;
+        default:
+            break;
+    }
+
+    if (!channel) {
+        // discard request by sending disconnected mode
+        multiplexer->send_dm_for_dlci = dlci;
+        return;
+    }
+    channel->connection = service->connection;
+    rfcomm_channel_state_machine(channel, event);
+}
+
+void rfcomm_channel_packet_handler(rfcomm_multiplexer_t * multiplexer,  uint8_t *packet, uint16_t size){
+    
+    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
+    const uint8_t frame_dlci = packet[0] >> 2;
+    uint8_t message_dlci; // used by commands in UIH(_PF) packets 
+    uint8_t message_len;  //   "
+    
+    // rfcomm: (1) command/control
+    // -- credits_offset = 1 if command == BT_RFCOMM_UIH_PF
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    // rfcomm: (2) length. if bit 0 is cleared, 2 byte length is used. (little endian)
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    // rfcomm: (3+length_offset) credits if credits_offset == 1
+    // rfcomm: (3+length_offest+credits_offset)
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+    
+    rfcomm_channel_event_t event;
+    rfcomm_channel_event_pn_t event_pn;
+    rfcomm_channel_event_rpn_t event_rpn;
+
+    // switch by rfcomm message type
+    switch(packet[1]) {
+            
+        case BT_RFCOMM_SABM:
+            event.type = CH_EVT_RCVD_SABM;
+            log_info("Received SABM #%u\n", frame_dlci);
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_UA:
+            event.type = CH_EVT_RCVD_UA;
+            log_info("Received UA #%u - channel opened\n",frame_dlci);
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_DISC:
+            event.type = CH_EVT_RCVD_DISC;
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_DM:
+        case BT_RFCOMM_DM_PF:
+            event.type = CH_EVT_RCVD_DM;
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_UIH_PF:
+        case BT_RFCOMM_UIH:
+
+            message_len  = packet[payload_offset+1] >> 1;
+
+            switch (packet[payload_offset]) {
+                case BT_RFCOMM_PN_CMD:
+                    message_dlci = packet[payload_offset+2];
+                    event_pn.super.type = CH_EVT_RCVD_PN;
+                    event_pn.priority = packet[payload_offset+4];
+                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
+                    event_pn.credits_outgoing = packet[payload_offset+9];
+                    log_info("Received UIH Parameter Negotiation Command for #%u\n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
+                    break;
+                    
+                case BT_RFCOMM_PN_RSP:
+                    message_dlci = packet[payload_offset+2];
+                    event_pn.super.type = CH_EVT_RCVD_PN_RSP;
+                    event_pn.priority = packet[payload_offset+4];
+                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
+                    event_pn.credits_outgoing = packet[payload_offset+9];
+                    log_info("UIH Parameter Negotiation Response max frame %u, credits %u\n",
+                            event_pn.max_frame_size, event_pn.credits_outgoing);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
+                    break;
+                    
+                case BT_RFCOMM_MSC_CMD: 
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    event.type = CH_EVT_RCVD_MSC_CMD;
+                    log_info("Received MSC CMD for #%u, \n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                    break;
+                    
+                case BT_RFCOMM_MSC_RSP:
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    event.type = CH_EVT_RCVD_MSC_RSP;
+                    log_info("Received MSC RSP for #%u\n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                    break;
+                    
+                case BT_RFCOMM_RPN_CMD:
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    switch (message_len){
+                        case 1:
+                            log_info("Received Remote Port Negotiation for #%u\n", message_dlci);
+                            event.type = CH_EVT_RCVD_RPN_REQ;
+                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                            break;
+                        case 8:
+                            log_info("Received Remote Port Negotiation (Info) for #%u\n", message_dlci);
+                            event_rpn.super.type = CH_EVT_RCVD_RPN_CMD;
+                            event_rpn.data.baud_rate = packet[payload_offset+3];
+                            event_rpn.data.flags = packet[payload_offset+4];
+                            event_rpn.data.flow_control = packet[payload_offset+5];
+                            event_rpn.data.xon  = packet[payload_offset+6];
+                            event_rpn.data.xoff = packet[payload_offset+7];
+                            event_rpn.data.parameter_mask_0 = packet[payload_offset+8];
+                            event_rpn.data.parameter_mask_1 = packet[payload_offset+9];
+                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_rpn);
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+                    
+                default:
+                    log_error("Received unknown UIH packet - 0x%02x\n", packet[payload_offset]); 
+                    break;
+            }
+            break;
+            
+        default:
+            log_error("Received unknown RFCOMM message type %x\n", packet[1]);
+            break;
+    }
+    
+    // trigger next action - example W4_PN_RSP: transition to SEND_SABM which only depends on "can send"
+    rfcomm_run();
+}
+
+void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    
+    // multiplexer handler
+    int handled = 0;
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            handled = rfcomm_multiplexer_hci_event_handler(packet, size);
+            break;
+        case L2CAP_DATA_PACKET:
+            handled = rfcomm_multiplexer_l2cap_packet_handler(channel, packet, size);
+            break;
+        default:
+            break;
+    }
+    
+    if (handled) {
+        rfcomm_run();
+        return;
+    }
+    
+    // we only handle l2cap packet over open multiplexer channel now
+    if (packet_type != L2CAP_DATA_PACKET) {
+        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
+        return;
+    }
+    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
+    if (!multiplexer || multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
+        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
+        return;
+    }
+    
+    // channel data ?
+    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
+    const uint8_t frame_dlci = packet[0] >> 2;
+    
+    if (frame_dlci && (packet[1] == BT_RFCOMM_UIH || packet[1] == BT_RFCOMM_UIH_PF)) {
+        rfcomm_channel_packet_handler_uih(multiplexer, packet, size);
+        rfcomm_run();
+        return;
+    }
+     
+    rfcomm_channel_packet_handler(multiplexer, packet, size);
+}
+
+static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel){
+    // log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u \n", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP) == 0) return 0;
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP) == 0) return 0;
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS) == 0) return 0;
+    if (channel->credits_outgoing == 0) return 0;
+    
+    return 1;
+}
+
+static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event){
+    
+    // log_info("rfcomm_channel_state_machine: state %u, state_var %04x, event %u\n", channel->state, channel->state_var ,event->type);
+    
+    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_DISC){
+        rfcomm_emit_channel_closed(channel);
+        channel->state = RFCOMM_CHANNEL_SEND_UA_AFTER_DISC;
+        return;
+    }
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_DM){
+        log_info("Received DM message for #%u\n", channel->dlci);
+        log_info("-> Closing channel locally for #%u\n", channel->dlci);
+        rfcomm_emit_channel_closed(channel);
+        rfcomm_channel_finalize(channel);
+        return;
+    }
+    
+    // remote port negotiation command - just accept everything for now
+    //
+    // "The RPN command can be used before a new DLC is opened and should be used whenever the port settings change."
+    // "The RPN command is specified as optional in TS 07.10, but it is mandatory to recognize and respond to it in RFCOMM. 
+    //   (Although the handling of individual settings are implementation-dependent.)"
+    //
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_RPN_CMD){
+        // control port parameters
+        rfcomm_channel_event_rpn_t *event_rpn = (rfcomm_channel_event_rpn_t*) event;
+        memcpy(&channel->rpn_data, &event_rpn->data, sizeof(rfcomm_rpn_data_t));
+        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+        return;
+    }
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_RPN_REQ){
+        // default rpn rsp
+        rfcomm_rpn_data_t rpn_data;
+        rpn_data.baud_rate = 0xa0;        /* 9600 bps */
+        rpn_data.flags = 0x03;            /* 8-n-1 */
+        rpn_data.flow_control = 0;        /* no flow control */
+        rpn_data.xon  = 0xd1;             /* XON */
+        rpn_data.xoff = 0xd3;             /* XOFF */
+        rpn_data.parameter_mask_0 = 0x7f; /* parameter mask, all values set */
+        rpn_data.parameter_mask_1 = 0x3f; /* parameter mask, all values set */
+        memcpy(&channel->rpn_data, &rpn_data, sizeof(rfcomm_rpn_data_t));
+        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+        return;
+    }
+    
+    // TODO: integrate in common swich
+    if (event->type == CH_EVT_READY_TO_SEND){
+        if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP){
+            log_info("Sending Remote Port Negotiation RSP for #%u\n", channel->dlci);
+            channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+            rfcomm_send_uih_rpn_rsp(multiplexer, channel->dlci, &channel->rpn_data);
+            return;
+        }
+    }
+    
+    rfcomm_channel_event_pn_t * event_pn = (rfcomm_channel_event_pn_t*) event;
+    
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_CLOSED:
+            switch (event->type){
+                case CH_EVT_RCVD_SABM:
+                    log_info("-> Inform app\n");
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
+                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
+                    rfcomm_emit_connection_request(channel);
+                    break;
+                case CH_EVT_RCVD_PN:
+                    rfcomm_channel_accept_pn(channel, event_pn);
+                    log_info("-> Inform app\n");
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
+                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
+                    rfcomm_emit_connection_request(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            switch (event->type){
+                case CH_EVT_RCVD_SABM:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+                    }
+                    break;
+                case CH_EVT_RCVD_PN:
+                    rfcomm_channel_accept_pn(channel, event_pn);
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+                    }
+                    break;
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP){
+                        log_info("Sending UIH Parameter Negotiation Respond for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+                        rfcomm_send_uih_pn_response(multiplexer, channel->dlci, channel->pn_priority, channel->max_frame_size);
+                    }
+                    else if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_UA){
+                        log_info("Sending UA #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+                        rfcomm_send_ua(multiplexer, channel->dlci);
+                    }
+                    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) && (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM)) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                        channel->state = RFCOMM_CHANNEL_DLC_SETUP;
+                    } 
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_MULTIPLEXER:
+            switch (event->type) {
+                case CH_EVT_MULTIPLEXER_READY:
+                    log_info("Muliplexer opened, sending UIH PN next\n");
+                    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_UIH_PN:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending UIH Parameter Negotiation Command for #%u (channel 0x%p)\n", channel->dlci, channel );
+                    channel->state = RFCOMM_CHANNEL_W4_PN_RSP;
+                    rfcomm_send_uih_pn_command(multiplexer, channel->dlci, channel->max_frame_size);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_PN_RSP:
+            switch (event->type){
+                case CH_EVT_RCVD_PN_RSP:
+                    // update max frame size
+                    if (channel->max_frame_size > event_pn->max_frame_size) {
+                        channel->max_frame_size = event_pn->max_frame_size;
+                    }
+                    // new credits
+                    channel->credits_outgoing = event_pn->credits_outgoing;
+                    channel->state = RFCOMM_CHANNEL_SEND_SABM_W4_UA;
+                    break;
+                default:
+                    break;
+            }
+            break;
+
+        case RFCOMM_CHANNEL_SEND_SABM_W4_UA:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending SABM #%u\n", channel->dlci);
+                    channel->state = RFCOMM_CHANNEL_W4_UA;
+                    rfcomm_send_sabm(multiplexer, channel->dlci);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_UA:
+            switch (event->type){
+                case CH_EVT_RCVD_UA:
+                    channel->state = RFCOMM_CHANNEL_DLC_SETUP;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_DLC_SETUP:
+            switch (event->type){
+                case CH_EVT_RCVD_MSC_CMD:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                    break;
+                case CH_EVT_RCVD_MSC_RSP:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP;
+                    break;
+                    
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD){
+                        log_info("Sending MSC CMD for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD;
+                        rfcomm_send_uih_msc_cmd(multiplexer, channel->dlci , 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
+                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP;
+                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS){
+                        log_info("Providing credits for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS;
+                        if (channel->new_credits_incoming) {
+                            uint8_t new_credits = channel->new_credits_incoming;
+                            channel->new_credits_incoming = 0;
+                            rfcomm_channel_send_credits(channel, new_credits);
+                        }
+                        break;
+
+                    }
+                    break;
+                default:
+                    break;
+            }
+            // finally done?
+            if (rfcomm_channel_ready_for_open(channel)){
+                channel->state = RFCOMM_CHANNEL_OPEN;
+                rfcomm_channel_opened(channel);
+            }
+            break;
+        
+        case RFCOMM_CHANNEL_OPEN:
+            switch (event->type){
+                case CH_EVT_RCVD_MSC_CMD:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                    break;
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
+                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->new_credits_incoming) {
+                        uint8_t new_credits = channel->new_credits_incoming;
+                        channel->new_credits_incoming = 0;
+                        rfcomm_channel_send_credits(channel, new_credits);
+                        break;
+                    }
+                    break;
+                case CH_EVT_RCVD_CREDITS: {
+                    // notify daemon -> might trigger re-try of parked connections
+                    uint8_t event[1] = { DAEMON_EVENT_NEW_RFCOMM_CREDITS };
+                    (*app_packet_handler)(channel->connection, DAEMON_EVENT_PACKET, channel->rfcomm_cid, event, sizeof(event));
+                    break;
+                }  
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_DM:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending DM_PF for #%u\n", channel->dlci);
+                    // don't emit channel closed - channel was never open
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_dm_pf(multiplexer, channel->dlci);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_DISC:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_disc(multiplexer, channel->dlci);
+                    rfcomm_emit_channel_closed(channel);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_UA_AFTER_DISC:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending UA after DISC for #%u\n", channel->dlci);
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_ua(multiplexer, channel->dlci);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+
+// MARK: RFCOMM RUN
+// process outstanding signaling tasks
+static void rfcomm_run(void){
+    
+    linked_item_t *it;
+    linked_item_t *next;
+    
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = next){
+
+        next = it->next;    // be prepared for removal of channel in state machine
+        
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        
+        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) {
+            // log_info("rfcomm_run cannot send l2cap packet for #%u, credits %u\n", multiplexer->l2cap_cid, multiplexer->l2cap_credits);
+            continue;
+        }
+        // log_info("rfcomm_run: multi 0x%08x, state %u\n", (int) multiplexer, multiplexer->state);
+
+        rfcomm_multiplexer_state_machine(multiplexer, MULT_EV_READY_TO_SEND);
+    }
+
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = next){
+
+        next = it->next;    // be prepared for removal of channel in state machine
+
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        rfcomm_multiplexer_t * multiplexer = channel->multiplexer;
+        
+        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) continue;
+     
+        rfcomm_channel_event_t event = { CH_EVT_READY_TO_SEND };
+        rfcomm_channel_state_machine(channel, &event);
+    }
+}
+
+// MARK: RFCOMM BTstack API
+
+void rfcomm_init(void){
+    rfcomm_client_cid_generator = 0;
+    rfcomm_multiplexers = NULL;
+    rfcomm_services     = NULL;
+    rfcomm_channels     = NULL;
+}
+
+// register packet handler
+void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                    uint16_t channel, uint8_t *packet, uint16_t size)){
+    app_packet_handler = handler;
+}
+
+// send packet over specific channel
+int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
+
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel){
+        log_error("rfcomm_send_internal cid %u doesn't exist!\n", rfcomm_cid);
+        return 0;
+    }
+    
+    if (!channel->credits_outgoing){
+        log_info("rfcomm_send_internal cid %u, no rfcomm outgoing credits!\n", rfcomm_cid);
+        return RFCOMM_NO_OUTGOING_CREDITS;
+    }
+
+    if (!channel->packets_granted){
+        log_info("rfcomm_send_internal cid %u, no rfcomm credits granted!\n", rfcomm_cid);
+        return RFCOMM_NO_OUTGOING_CREDITS;
+    }
+    
+    // log_info("rfcomm_send_internal: len %u... outgoing credits %u, l2cap credit %us, granted %u\n",
+    //        len, channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
+    
+
+    // send might cause l2cap to emit new credits, update counters first
+    channel->credits_outgoing--;
+    int packets_granted_decreased = 0;
+    if (channel->packets_granted) {
+        channel->packets_granted--;
+        packets_granted_decreased++;
+    }
+    
+    int result = rfcomm_send_uih_data(channel->multiplexer, channel->dlci, data, len);
+    
+    if (result != 0) {
+        channel->credits_outgoing++;
+        channel->packets_granted += packets_granted_decreased;
+        log_info("rfcomm_send_internal: error %d\n", result);
+        return result;
+    }
+    
+    // log_info("rfcomm_send_internal: now outgoing credits %u, l2cap credit %us, granted %u\n",
+    //        channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
+
+    rfcomm_hand_out_credits();
+    
+    return result;
+}
+
+void rfcomm_create_channel2(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t incoming_flow_control, uint8_t initial_credits){
+    log_info("rfcomm_create_channel_internal to %s, at channel #%02x, flow control %u, init credits %u\n",  bd_addr_to_str(*addr), server_channel,
+             incoming_flow_control, initial_credits);
+    
+    // create new multiplexer if necessary
+    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_addr(addr);
+    if (!multiplexer) {
+        multiplexer = rfcomm_multiplexer_create_for_addr(addr);
+        if (!multiplexer){
+            rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
+            return;
+        }
+        multiplexer->outgoing = 1;
+        multiplexer->state = RFCOMM_MULTIPLEXER_W4_CONNECT;
+    }
+    
+    // prepare channel
+    rfcomm_channel_t * channel = rfcomm_channel_create(multiplexer, NULL, server_channel);
+    if (!channel){
+        rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
+        return;
+    }
+    channel->connection = connection;
+    channel->incoming_flow_control = incoming_flow_control;
+    channel->new_credits_incoming  = initial_credits;
+    
+    // start multiplexer setup
+    if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
+        
+        channel->state = RFCOMM_CHANNEL_W4_MULTIPLEXER;
+        
+        l2cap_create_channel_internal(connection, rfcomm_packet_handler, *addr, PSM_RFCOMM, l2cap_max_mtu());
+        
+        return;
+    }
+    
+    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
+    
+    // start connecting, if multiplexer is already up and running
+    rfcomm_run();
+}
+
+void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits){
+    rfcomm_create_channel2(connection, addr, server_channel, 1, initial_credits);
+}
+
+void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t server_channel){
+    rfcomm_create_channel2(connection, addr, server_channel, 0, 0x30);
+}
+
+void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (channel) {
+        channel->state = RFCOMM_CHANNEL_SEND_DISC;
+    }
+    
+    // process
+    rfcomm_run();
+}
+
+
+void rfcomm_register_service2(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){
+    // check if already registered
+    rfcomm_service_t * service = rfcomm_service_for_channel(channel);
+    if (service){
+        rfcomm_emit_service_registered(connection, RFCOMM_CHANNEL_ALREADY_REGISTERED, channel);
+        return;
+    }
+    
+    // alloc structure
+    service = (rfcomm_service_t*)btstack_memory_rfcomm_service_get();
+    if (!service) {
+        rfcomm_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, channel);
+        return;
+    }
+    
+    // register with l2cap if not registered before, max MTU
+    if (linked_list_empty(&rfcomm_services)){
+        l2cap_register_service_internal(NULL, rfcomm_packet_handler, PSM_RFCOMM, 0xffff);
+    }
+    
+    // fill in 
+    service->connection     = connection;
+    service->server_channel = channel;
+    service->max_frame_size = max_frame_size;
+    service->incoming_flow_control = incoming_flow_control;
+    service->incoming_initial_credits = initial_credits;
+    
+    // add to services list
+    linked_list_add(&rfcomm_services, (linked_item_t *) service);
+    
+    // done
+    rfcomm_emit_service_registered(connection, 0, channel);
+}
+
+void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits){
+    rfcomm_register_service2(connection, channel, max_frame_size, 1, initial_credits);
+}
+
+void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
+    rfcomm_register_service2(connection, channel, max_frame_size, 0, 0x30);
+}
+
+void rfcomm_unregister_service_internal(uint8_t service_channel){
+    rfcomm_service_t *service = rfcomm_service_for_channel(service_channel);
+    if (!service) return;
+    linked_list_remove(&rfcomm_services, (linked_item_t *) service);
+    btstack_memory_rfcomm_service_free(service);
+    
+    // unregister if no services active
+    if (linked_list_empty(&rfcomm_services)){
+        // bt_send_cmd(&l2cap_unregister_service, PSM_RFCOMM);
+        l2cap_unregister_service_internal(NULL, PSM_RFCOMM);
+    }
+}
+
+void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
+    log_info("Received Accept Connction\n");
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED;
+            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_PN){
+                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+            }
+            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM){
+                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+            }
+            break;
+        default:
+            break;
+    }
+
+    // process
+    rfcomm_run();
+}
+
+void rfcomm_decline_connection_internal(uint16_t rfcomm_cid){
+    log_info("Received Decline Connction\n");
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            channel->state = RFCOMM_CHANNEL_SEND_DM;
+            break;
+        default:
+            break;
+    }
+
+    // process
+    rfcomm_run();
+}
+
+void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits){
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    if (!channel->incoming_flow_control) return;
+    channel->new_credits_incoming += credits;
+
+    // process
+    rfcomm_run();
+}
+
+//
+void rfcomm_close_connection(void *connection){
+    linked_item_t *it;
+    
+    // close open channels
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *)it;
+        if (channel->connection != connection) continue;
+        channel->state = RFCOMM_CHANNEL_SEND_DISC;
+    }
+    
+    // unregister services
+    it = (linked_item_t *) &rfcomm_services;
+    while (it->next) {
+        rfcomm_service_t * service = (rfcomm_service_t *) it->next;
+        if (service->connection == connection){
+            it->next = it->next->next;
+            btstack_memory_rfcomm_service_free(service);
+        } else {
+            it = it->next;
+        }
+    }
+
+    // process
+    rfcomm_run();
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/rfcomm.h	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,304 @@
+/*
+ * 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;
+*/
+
+enum {
+    RFCOMM_CHANNEL_STATE_VAR_NONE            = 0,
+    RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED = 1 << 0,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_PN         = 1 << 1,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_RPN        = 1 << 2,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM       = 1 << 3,
+    
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD    = 1 << 4,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP    = 1 << 5,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP     = 1 << 6,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_INFO   = 1 << 7,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP    = 1 << 8,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_UA         = 1 << 9,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD    = 1 << 10,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP    = 1 << 11,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS    = 1 << 12,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD    = 1 << 13,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP    = 1 << 14,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS    = 1 << 15,
+};
+typedef uint16_t RFCOMM_CHANNEL_STATE_VAR;
+
+typedef enum {
+    CH_EVT_RCVD_SABM = 1,
+    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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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/sdp.c	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ * Implementation of the Service Discovery Protocol Server 
+ */
+
+#include "sdp.h"
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include <btstack/sdp_util.h>
+
+#include "hci_dump.h"
+#include "l2cap.h"
+
+#include "debug.h"
+
+// max reserved ServiceRecordHandle
+#define maxReservedServiceRecordHandle 0xffff
+
+// max SDP response
+#define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
+
+static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+
+// registered service records
+static linked_list_t sdp_service_records = NULL;
+
+// our handles start after the reserved range
+static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2;
+
+static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
+
+static void (*app_packet_handler)(void * connection, uint8_t packet_type,
+                                  uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
+
+static uint16_t l2cap_cid = 0;
+static uint16_t sdp_response_size = 0;
+
+void sdp_init(){
+    // register with l2cap psm sevices - max MTU
+    l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff);
+}
+
+// register packet handler
+void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                 uint16_t channel, uint8_t *packet, uint16_t size)){
+	app_packet_handler = handler;
+    l2cap_cid = 0;
+}
+
+uint32_t sdp_get_service_record_handle(uint8_t * record){
+    uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
+    if (!serviceRecordHandleAttribute) return 0;
+    if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
+    if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
+    return READ_NET_32(serviceRecordHandleAttribute, 1); 
+}
+
+// data: event(8), len(8), status(8), service_record_handle(32)
+static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
+    if (!app_packet_handler) return;
+    uint8_t event[7];
+    event[0] = SDP_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_32(event, 3, handle);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+	(*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        if (item->service_record_handle == handle){
+            return item;
+        }
+    }
+    return NULL;
+}
+
+// get next free, unregistered service record handle
+uint32_t sdp_create_service_record_handle(void){
+    uint32_t handle = 0;
+    do {
+        handle = sdp_next_service_record_handle++;
+        if (sdp_get_record_for_handle(handle)) handle = 0;
+    } while (handle == 0);
+    return handle;
+}
+
+#ifdef EMBEDDED
+
+// register service record internally - this special version doesn't copy the record, it should not be freeed
+// pre: AttributeIDs are in ascending order
+// pre: ServiceRecordHandle is first attribute and valid
+// pre: record
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){
+    // get user record handle
+    uint32_t record_handle = record_item->service_record_handle;
+    // get actual record
+    uint8_t *record = record_item->service_record;
+    
+    // check for ServiceRecordHandle attribute, returns pointer or null
+    uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
+    if (!req_record_handle) {
+        log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n");
+        return 0;
+    }
+    
+    // validate service record handle is not in reserved range
+    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
+    
+    // check if already in use
+    if (record_handle) {
+        if (sdp_get_record_for_handle(record_handle)) {
+            record_handle = 0;
+        }
+    }
+    
+    // create new handle if needed
+    if (!record_handle){
+        record_handle = sdp_create_service_record_handle();
+        // Write the handle back into the record too
+        record_item->service_record_handle = record_handle;
+        sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
+    }
+    
+    // add to linked list
+    linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
+    
+    sdp_emit_service_registered(connection, 0, record_item->service_record_handle);
+    
+    return record_handle;
+}
+
+#else
+
+// AttributeIDList used to remove ServiceRecordHandle
+static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
+
+// register service record internally - the normal version creates a copy of the record
+// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, uint8_t * record){
+
+    // dump for now
+    // printf("Register service record\n");
+    // de_dump_data_element(record);
+    
+    // get user record handle
+    uint32_t record_handle = sdp_get_service_record_handle(record);
+
+    // validate service record handle is not in reserved range
+    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
+    
+    // check if already in use
+    if (record_handle) {
+        if (sdp_get_record_for_handle(record_handle)) {
+            record_handle = 0;
+        }
+    }
+    
+    // create new handle if needed
+    if (!record_handle){
+        record_handle = sdp_create_service_record_handle();
+    }
+    
+    // calculate size of new service record: DES (2 byte len) 
+    // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
+    uint16_t recordSize =  3 + (3 + 5) + de_get_data_size(record);
+        
+    // alloc memory for new service_record_item
+    service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
+    if (!newRecordItem) {
+        sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED);
+        return 0;
+    }
+    // link new service item to client connection
+    newRecordItem->connection = connection;
+    
+    // set new handle
+    newRecordItem->service_record_handle = record_handle;
+
+    // create updated service record
+    uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
+    
+    // create DES for new record
+    de_create_sequence(newRecord);
+    
+    // set service record handle
+    de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
+    de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
+    
+    // add other attributes
+    sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
+    
+    // dump for now
+    // de_dump_data_element(newRecord);
+    // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord));
+    
+    // add to linked list
+    linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
+    
+    sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle);
+
+    return record_handle;
+}
+
+#endif
+
+// unregister service record internally
+// 
+// makes sure one client cannot remove service records of other clients
+//
+void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){
+    service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
+    if (record_item && record_item->connection == connection) {
+        linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
+    }
+}
+
+// remove all service record for a client connection
+void sdp_unregister_services_for_connection(void *connection){
+    linked_item_t *it = (linked_item_t *) &sdp_service_records;
+    while (it->next){
+        service_record_item_t *record_item = (service_record_item_t *) it->next;
+        if (record_item->connection == connection){
+            it->next = it->next->next;
+#ifndef EMBEDDED
+            free(record_item);
+#endif
+        } else {
+            it = it->next;
+        }
+    }
+}
+
+// PDU
+// PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
+
+int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
+    sdp_response_buffer[0] = SDP_ErrorResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, 2);
+    net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
+    return 7;
+}
+
+int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint8_t * serviceSearchPattern = &packet[5];
+    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
+    uint16_t  maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
+    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
+    
+    // calc maxumumServiceRecordCount based on remote MTU
+    uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
+    
+    // continuation state contains index of next service record to examine
+    int      continuation = 0;
+    uint16_t continuation_index = 0;
+    if (continuationState[0] == 2){
+        continuation_index = READ_NET_16(continuationState, 1);
+    }
+    
+    // get and limit total count
+    linked_item_t *it;
+    uint16_t total_service_count   = 0;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        total_service_count++;
+    }
+    if (total_service_count > maximumServiceRecordCount){
+        total_service_count = maximumServiceRecordCount;
+    }
+    
+    // ServiceRecordHandleList at 9
+    uint16_t pos = 9;
+    uint16_t current_service_count  = 0;
+    uint16_t current_service_index  = 0;
+    uint16_t matching_service_count = 0;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
+        service_record_item_t * item = (service_record_item_t *) it;
+
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        matching_service_count++;
+        
+        if (current_service_index < continuation_index) continue;
+
+        net_store_32(sdp_response_buffer, pos, item->service_record_handle);
+        pos += 4;
+        current_service_count++;
+        
+        if (matching_service_count >= total_service_count) break;
+
+        if (current_service_count >= maxNrServiceRecordsPerResponse){
+            continuation = 1;
+            continuation_index = current_service_index + 1;
+            break;
+        }
+    }
+    
+    // Store continuation state
+    if (continuation) {
+        sdp_response_buffer[pos++] = 2;
+        net_store_16(sdp_response_buffer, pos, continuation_index);
+        pos += 2;
+    } else {
+        sdp_response_buffer[pos++] = 0;
+    }
+
+    // header
+    sdp_response_buffer[0] = SDP_ServiceSearchResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
+    net_store_16(sdp_response_buffer, 5, total_service_count);
+    net_store_16(sdp_response_buffer, 7, current_service_count);
+    
+    return pos;
+}
+
+int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint32_t  serviceRecordHandle = READ_NET_32(packet, 5);
+    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 9);
+    uint8_t * attributeIDList = &packet[11];
+    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
+    uint8_t * continuationState = &packet[11+attributeIDListLen];
+    
+    // calc maximumAttributeByteCount based on remote MTU
+    uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
+    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
+        maximumAttributeByteCount = maximumAttributeByteCount2;
+    }
+    
+    // continuation state contains the offset into the complete response
+    uint16_t continuation_offset = 0;
+    if (continuationState[0] == 2){
+        continuation_offset = READ_NET_16(continuationState, 1);
+    }
+    
+    // get service record
+    service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
+    if (!item){
+        // service record handle doesn't exist
+        return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
+    }
+    
+    
+    // AttributeList - starts at offset 7
+    uint16_t pos = 7;
+    
+    if (continuation_offset == 0){
+        
+        // get size of this record
+        uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
+        
+        // store DES
+        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
+        maximumAttributeByteCount -= 3;
+        pos += 3;
+    }
+
+    // copy maximumAttributeByteCount from record
+    uint16_t bytes_used;
+    int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
+    pos += bytes_used;
+    
+    uint16_t attributeListByteCount = pos - 7;
+
+    if (complete) {
+        sdp_response_buffer[pos++] = 0;
+    } else {
+        continuation_offset += bytes_used;
+        sdp_response_buffer[pos++] = 2;
+        net_store_16(sdp_response_buffer, pos, continuation_offset);
+        pos += 2;
+    }
+
+    // header
+    sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
+    net_store_16(sdp_response_buffer, 5, attributeListByteCount); 
+    
+    return pos;
+}
+
+static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
+    uint16_t total_response_size = 0;
+    linked_item_t *it;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        
+        // for all service records that match
+        total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
+    }
+    return total_response_size;
+}
+
+int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // SDP header before attribute sevice list: 7
+    // Continuation, worst case: 5
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint8_t * serviceSearchPattern = &packet[5];
+    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
+    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
+    uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
+    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
+    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
+    
+    // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
+    uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
+    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
+        maximumAttributeByteCount = maximumAttributeByteCount2;
+    }
+    
+    // continuation state contains: index of next service record to examine
+    // continuation state contains: byte offset into this service record
+    uint16_t continuation_service_index = 0;
+    uint16_t continuation_offset = 0;
+    if (continuationState[0] == 4){
+        continuation_service_index = READ_NET_16(continuationState, 1);
+        continuation_offset = READ_NET_16(continuationState, 3);
+    }
+
+    // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount);
+    
+    // AttributeLists - starts at offset 7
+    uint16_t pos = 7;
+    
+    // add DES with total size for first request
+    if (continuation_service_index == 0 && continuation_offset == 0){
+        uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
+        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
+        // log_info("total response size %u\n", total_response_size);
+        pos += 3;
+        maximumAttributeByteCount -= 3;
+    }
+    
+    // create attribute list
+    int      first_answer = 1;
+    int      continuation = 0;
+    uint16_t current_service_index = 0;
+    linked_item_t *it = (linked_item_t *) sdp_service_records;
+    for ( ; it ; it = it->next, ++current_service_index){
+        service_record_item_t * item = (service_record_item_t *) it;
+        
+        if (current_service_index < continuation_service_index ) continue;
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+
+        if (continuation_offset == 0){
+            
+            // get size of this record
+            uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
+            
+            // stop if complete record doesn't fits into response but we already have a partial response
+            if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
+                continuation = 1;
+                break;
+            }
+            
+            // store DES
+            de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
+            pos += 3;
+            maximumAttributeByteCount -= 3;
+        }
+        
+        first_answer = 0;
+    
+        // copy maximumAttributeByteCount from record
+        uint16_t bytes_used;
+        int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
+        pos += bytes_used;
+        maximumAttributeByteCount -= bytes_used;
+        
+        if (complete) {
+            continuation_offset = 0;
+            continue;
+        }
+        
+        continuation = 1;
+        continuation_offset += bytes_used;
+        break;
+    }
+    
+    uint16_t attributeListsByteCount = pos - 7;
+    
+    // Continuation State
+    if (continuation){
+        sdp_response_buffer[pos++] = 4;
+        net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
+        pos += 2;
+        net_store_16(sdp_response_buffer, pos, continuation_offset);
+        pos += 2;
+    } else {
+        // complete
+        sdp_response_buffer[pos++] = 0;
+    }
+        
+    // create SDP header
+    sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
+    net_store_16(sdp_response_buffer, 5, attributeListsByteCount);
+    
+    return pos;
+}
+
+static void sdp_try_respond(void){
+    if (!sdp_response_size ) return;
+    if (!l2cap_cid) return;
+    if (!l2cap_can_send_packet_now(l2cap_cid)) return;
+    
+    // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
+    uint16_t size = sdp_response_size;
+    sdp_response_size = 0;
+    l2cap_send_internal(l2cap_cid, sdp_response_buffer, size);
+}
+
+// we assume that we don't get two requests in a row
+static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+	uint16_t transaction_id;
+    SDP_PDU_ID_t pdu_id;
+    uint16_t remote_mtu;
+    // uint16_t param_len;
+    
+	switch (packet_type) {
+			
+		case L2CAP_DATA_PACKET:
+            pdu_id = (SDP_PDU_ID_t) packet[0];
+            transaction_id = READ_NET_16(packet, 1);
+            // param_len = READ_NET_16(packet, 3);
+            remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
+            // account for our buffer
+            if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
+                remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
+            }
+            
+            // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu);
+            switch (pdu_id){
+                    
+                case SDP_ServiceSearchRequest:
+                    sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
+                    break;
+                                        
+                case SDP_ServiceAttributeRequest:
+                    sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
+                    break;
+                    
+                case SDP_ServiceSearchAttributeRequest:
+                    sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
+                    break;
+                    
+                default:
+                    sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
+                    break;
+            }
+            
+            sdp_try_respond();
+            
+			break;
+			
+		case HCI_EVENT_PACKET:
+			
+			switch (packet[0]) {
+
+				case L2CAP_EVENT_INCOMING_CONNECTION:
+                    if (l2cap_cid) {
+                        // CONNECTION REJECTED DUE TO LIMITED RESOURCES 
+                        l2cap_decline_connection_internal(channel, 0x0d);
+                        break;
+                    }
+                    // accept
+                    l2cap_cid = channel;
+                    sdp_response_size = 0;
+                    l2cap_accept_connection_internal(channel);
+					break;
+                    
+                case L2CAP_EVENT_CHANNEL_OPENED:
+                    if (packet[2]) {
+                        // open failed -> reset
+                        l2cap_cid = 0;
+                    }
+                    break;
+
+                case L2CAP_EVENT_CREDITS:
+                case DAEMON_EVENT_HCI_PACKET_SENT:
+                    sdp_try_respond();
+                    break;
+                
+                case L2CAP_EVENT_CHANNEL_CLOSED:
+                    if (channel == l2cap_cid){
+                        // reset
+                        l2cap_cid = 0;
+                    }
+                    break;
+					                    
+				default:
+					// other event
+					break;
+			}
+			break;
+			
+		default:
+			// other packet type
+			break;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/sdp.h	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <btstack/linked_list.h>
+
+#include "config.h"
+
+typedef enum {
+	SDP_ErrorResponse = 1,
+	SDP_ServiceSearchRequest,
+	SDP_ServiceSearchResponse,
+	SDP_ServiceAttributeRequest,
+	SDP_ServiceAttributeResponse,
+	SDP_ServiceSearchAttributeRequest,
+	SDP_ServiceSearchAttributeResponse
+} SDP_PDU_ID_t;
+
+// service record
+// -- uses user_data field for actual
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t   item;
+    
+    // client connection
+    void *  connection;
+    
+    // data is contained in same memory
+    uint32_t        service_record_handle;
+    uint8_t         service_record[0];
+} service_record_item_t;
+
+
+void sdp_init(void);
+
+void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                 uint16_t channel, uint8_t *packet, uint16_t size));
+
+#ifdef EMBEDDED
+// register service record internally - the normal version creates a copy of the record
+// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item);
+#else
+// register service record internally - this special version doesn't copy the record, it cannot be freeed
+// pre: AttributeIDs are in ascending order
+// pre: ServiceRecordHandle is first attribute and valid
+// pre: record
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, uint8_t * service_record);
+#endif
+
+// unregister service record internally
+void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle);
+
+//
+void sdp_unregister_services_for_connection(void *connection);
+
+//
+int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu);
+int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu);
+int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/sdp_util.c	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  sdp_util.c
+ */
+
+#include <btstack/sdp_util.h>
+#include <btstack/utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>   // PRIx32
+
+// workaround for missing PRIx32 on mspgcc (16-bit MCU)
+#ifndef PRIx32
+#warning Using own: #define PRIx32 "lx"
+#define PRIx32 "lx"
+#endif
+
+// date element type names
+const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"};
+
+// Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
+const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
+    0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+
+void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){
+    memcpy(uuid, sdp_bluetooth_base_uuid, 16);
+    net_store_32(uuid, 0, shortUUID);
+}
+
+// MARK: DataElement getter
+de_size_t de_get_size_type(uint8_t *header){
+    return (de_size_t) (header[0] & 7);
+}
+
+de_type_t de_get_element_type(uint8_t *header){
+    return (de_type_t) (header[0] >> 3);
+}
+
+int de_get_header_size(uint8_t * header){
+    de_size_t de_size = de_get_size_type(header);
+    if (de_size <= DE_SIZE_128) {
+        return 1;
+    }
+    return 1 + (1 << (de_size-DE_SIZE_VAR_8));
+}
+
+int de_get_data_size(uint8_t * header){
+    uint32_t result = 0;
+    de_type_t de_type = de_get_element_type(header);
+    de_size_t de_size = de_get_size_type(header);
+    switch (de_size){
+        case DE_SIZE_VAR_8:
+            result = header[1];
+            break;
+        case DE_SIZE_VAR_16:
+            result = READ_NET_16(header,1);
+            break;
+        case DE_SIZE_VAR_32:
+            result = READ_NET_32(header,1);
+            break;
+        default:
+        // case DE_SIZE_8:
+        // case DE_SIZE_16:
+        // case DE_SIZE_32:
+        // case DE_SIZE_64:
+        // case DE_SIZE_128:
+            if (de_type == DE_NIL) return 0;
+            return 1 << de_size;
+    }
+    return result;    
+}
+
+int de_get_len(uint8_t *header){
+    return de_get_header_size(header) + de_get_data_size(header); 
+}
+
+// @returns: element is valid UUID
+int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
+    de_type_t uuidType = de_get_element_type(element);
+    de_size_t uuidSize = de_get_size_type(element);
+    if (uuidType != DE_UUID) return 0;
+    uint32_t shortUUID;
+    switch (uuidSize){
+        case DE_SIZE_16:
+            shortUUID = READ_NET_16(element, 1);
+            break;
+        case DE_SIZE_32:
+            shortUUID = READ_NET_32(element, 1);
+            break;
+        case DE_SIZE_128:
+            memcpy(uuid128, element+1, 16);
+            return 1;
+        default:
+            return 0;
+    }
+    sdp_normalize_uuid(uuid128, shortUUID);
+    return 1;
+}
+
+// functions to create record
+static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){
+    header[0] = (type << 3) | size; 
+}
+
+void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){
+    header[0] = (type << 3) | size; 
+    switch (size){
+        case DE_SIZE_VAR_8:
+            header[1] = len;
+            break;
+        case DE_SIZE_VAR_16:
+            net_store_16(header, 1, len);
+            break;
+        case DE_SIZE_VAR_32:
+            net_store_32(header, 1, len);
+            break;
+        default:
+            break;
+    }
+}
+
+// MARK: DataElement creation
+
+/* starts a new sequence in empty buffer - first call */
+void de_create_sequence(uint8_t *header){
+    de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
+};
+
+/* starts a sub-sequence, @returns handle for sub-sequence */
+uint8_t * de_push_sequence(uint8_t *header){
+    int element_len = de_get_len(header);
+    de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
+    return header + element_len;
+}
+
+/* closes the current sequence and updates the parent sequence */
+void de_pop_sequence(uint8_t * parent, uint8_t * child){
+    int child_len = de_get_len(child);
+    int data_size_parent = READ_NET_16(parent,1);
+    net_store_16(parent, 1, data_size_parent + child_len);
+}
+
+/* adds a single number value and 16+32 bit UUID to the sequence */
+void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){
+    int data_size   = READ_NET_16(seq,1);
+    int element_size = 1;   // e.g. for DE_TYPE_NIL
+    de_store_descriptor(seq+3+data_size, type, size); 
+    switch (size){
+        case DE_SIZE_8:
+            if (type != DE_NIL){
+                seq[4+data_size] = value;
+                element_size = 2;
+            }
+            break;
+        case DE_SIZE_16:
+            net_store_16(seq, 4+data_size, value);
+            element_size = 3;
+            break;
+        case DE_SIZE_32:
+            net_store_32(seq, 4+data_size, value);
+            element_size = 5;
+            break;
+        default:
+            break;
+    }
+    net_store_16(seq, 1, data_size+element_size);
+}
+
+/* add a single block of data, e.g. as DE_STRING, DE_URL */
+void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){
+    int data_size   = READ_NET_16(seq,1);
+    if (size > 0xff) {
+        // use 16-bit lengh information (3 byte header)
+        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); 
+        data_size += 3;
+    } else {
+        // use 8-bit lengh information (2 byte header)
+        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); 
+        data_size += 2;
+    }
+    memcpy( seq + 3 + data_size, data, size);
+    data_size += size;
+    net_store_16(seq, 1, data_size);
+}
+
+void de_add_uuid128(uint8_t * seq, uint8_t * uuid){
+    int data_size   = READ_NET_16(seq,1);
+    de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); 
+    memcpy( seq + 4 + data_size, uuid, 16);
+    net_store_16(seq, 1, data_size+1+16);
+}
+
+void sdp_add_attribute(uint8_t *seq, uint16_t attributeID, uint8_t attributeValue){
+}
+
+// MARK: DataElementSequence traversal
+typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context);
+static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){
+    de_type_t type = de_get_element_type(element);
+    if (type != DE_DES) return;
+    int pos = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    while (pos < end_pos){
+        de_type_t elemType = de_get_element_type(element + pos);
+        de_size_t elemSize = de_get_size_type(element + pos);
+        uint8_t done = (*handler)(element + pos, elemType, elemSize, context); 
+        if (done) break;
+        pos += de_get_len(element + pos);
+    }
+}
+
+// MARK: AttributeList traversal
+typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context);
+static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){
+    de_type_t type = de_get_element_type(element);
+    if (type != DE_DES) return;
+    int pos = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    while (pos < end_pos){
+        de_type_t idType = de_get_element_type(element + pos);
+        de_size_t idSize = de_get_size_type(element + pos);
+        if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type
+        uint16_t attribute_id = READ_NET_16(element, pos + 1);
+        pos += 3;
+        if (pos >= end_pos) break; // array out of bounds
+        de_type_t valueType = de_get_element_type(element + pos);
+        de_size_t valueSize = de_get_size_type(element + pos);
+        uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); 
+        if (done) break;
+        pos += de_get_len(element + pos);
+    }
+}
+
+// MARK: AttributeID in AttributeIDList 
+// attribute ID in AttributeIDList
+// context { result, attributeID }
+struct sdp_context_attributeID_search {
+    int result;
+    uint16_t attributeID;
+};
+static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context;
+    if (type != DE_UINT) return 0;
+    switch (size) {
+        case DE_SIZE_16:
+            if (READ_NET_16(element, 1) == context->attributeID) {
+                context->result = 1;
+                return 1;
+            }
+            break;
+        case DE_SIZE_32:
+            if (READ_NET_16(element, 1) <= context->attributeID
+            &&  context->attributeID <= READ_NET_16(element, 3)) {
+                context->result = 1;
+                return 1;
+            }
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){
+    struct sdp_context_attributeID_search attributeID_search;
+    attributeID_search.result = 0;
+    attributeID_search.attributeID = attributeID;
+    de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search);
+    return attributeID_search.result;
+}
+
+// MARK: Append Attributes for AttributeIDList
+// pre: buffer contains DES with 2 byte length field
+struct sdp_context_append_attributes {
+    uint8_t * buffer;
+    uint16_t startOffset;     // offset of when to start copying
+    uint16_t maxBytes;
+    uint16_t usedBytes;
+    uint8_t *attributeIDList;
+};
+
+static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context;
+    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
+        // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute)
+        uint16_t data_size = READ_NET_16(context->buffer, 1);
+        int attribute_len = de_get_len(attributeValue);
+        if (3 + data_size + (3 + attribute_len) <= context->maxBytes) {
+            // copy Attribute
+            de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID);   
+            data_size += 3; // 3 bytes
+            memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len);
+            net_store_16(context->buffer,1,data_size+attribute_len);
+        } else {
+            // not enought space left -> continue with previous element
+            return 1;
+        }
+    }
+    return 0;
+}
+
+// maxBytes: maximal size of data element sequence
+uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){
+    struct sdp_context_append_attributes context;
+    context.buffer = buffer;
+    context.maxBytes = maxBytes;
+    context.usedBytes = 0;
+    context.startOffset = startOffset;
+    context.attributeIDList = attributeIDList;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context);
+    return context.usedBytes;
+}
+
+// MARK: Filter attributes that match attribute list from startOffset and a max nr bytes
+struct sdp_context_filter_attributes {
+    uint8_t * buffer;
+    uint16_t startOffset;     // offset of when to start copying
+    uint16_t maxBytes;
+    uint16_t usedBytes;
+    uint8_t *attributeIDList;
+    int      complete;
+};
+
+// copy data with given start offset and max bytes, returns OK if all data has been copied
+static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){
+    int ok = 1;
+    uint16_t remainder_len = len - context->startOffset;
+    if (context->maxBytes < remainder_len){
+        remainder_len = context->maxBytes;
+        ok = 0;
+    }
+    memcpy(context->buffer, &data[context->startOffset], remainder_len);
+    context->usedBytes += remainder_len;
+    context->buffer    += remainder_len;
+    context->maxBytes  -= remainder_len;
+    context->startOffset = 0;
+    return ok;
+}
+
+static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context;
+
+    if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0;
+
+    // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)}
+
+    // handle Attribute ID
+    if (context->startOffset >= 3){
+        context->startOffset -= 3;
+    } else {
+        uint8_t idBuffer[3];
+        de_store_descriptor(idBuffer, DE_UINT,  DE_SIZE_16);
+        net_store_16(idBuffer,1,attributeID);
+        
+        int ok = spd_append_range(context, 3, idBuffer);
+        if (!ok) {
+            context->complete = 0;
+            return 1;
+        }
+    }
+    
+    // handle Attribute Value
+    int attribute_len = de_get_len(attributeValue);
+    if (context->startOffset >= attribute_len) {
+        context->startOffset -= attribute_len;
+        return 0;
+    }
+    
+    int ok = spd_append_range(context, attribute_len, attributeValue);
+    if (!ok) {
+        context->complete = 0;
+        return 1;
+    }
+    return 0;
+}
+
+int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){
+
+    struct sdp_context_filter_attributes context;
+    context.buffer = buffer;
+    context.maxBytes = maxBytes;
+    context.usedBytes = 0;
+    context.startOffset = startOffset;
+    context.attributeIDList = attributeIDList;
+    context.complete = 1;
+
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context);
+
+    *usedBytes = context.usedBytes;
+    return context.complete;
+}
+
+// MARK: Get sum of attributes matching attribute list
+struct sdp_context_get_filtered_size {
+    uint8_t *attributeIDList;
+    uint16_t size;
+};
+
+static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context;
+    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
+        context->size += 3 + de_get_len(attributeValue);
+    }
+    return 0;
+}
+
+int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){
+    struct sdp_context_get_filtered_size context;
+    context.size = 0;
+    context.attributeIDList = attributeIDList;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context);
+    return context.size;
+}
+
+// MARK: Get AttributeValue for AttributeID
+// find attribute (ELEMENT) by ID
+struct sdp_context_attribute_by_id {
+    uint16_t  attributeID;
+    uint8_t * attributeValue;
+};
+static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context;
+    if (attributeID == context->attributeID) {
+        context->attributeValue = attributeValue;
+        return 1;
+    }
+    return 0;
+}
+
+uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){
+    struct sdp_context_attribute_by_id context;
+    context.attributeValue = NULL;
+    context.attributeID = attributeID;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context);
+    return context.attributeValue;
+}
+
+// MARK: Set AttributeValue for AttributeID
+struct sdp_context_set_attribute_for_id {
+    uint16_t  attributeID;
+    uint32_t  attributeValue;
+    uint8_t   attributeFound;
+};
+static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context;
+    if (attributeID == context->attributeID) {
+        context->attributeFound = 1;
+        switch (size){
+            case DE_SIZE_8:
+                if (attributeType != DE_NIL){
+                    attributeValue[1] = context->attributeValue;
+                }
+                break;
+            case DE_SIZE_16:
+                net_store_16(attributeValue, 1, context->attributeValue);
+                break;
+            case DE_SIZE_32:
+                net_store_32(attributeValue, 1, context->attributeValue);
+                break;
+                // Might want to support STRINGS to, copy upto original length
+            default:
+                break;
+        }        
+        return 1;
+    }
+    return 0;
+}
+uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){
+    struct sdp_context_set_attribute_for_id context;
+    context.attributeID = attributeID;
+    context.attributeValue = value;
+    context.attributeFound = 0;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context);
+    return context.attributeFound;
+}
+
+// MARK: ServiceRecord contains UUID
+// service record contains UUID
+// context { normalizedUUID }
+struct sdp_context_contains_uuid128 {
+    uint8_t * uuid128;
+    int result;
+};
+int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128);
+static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context;
+    uint8_t normalizedUUID[16];
+    if (type == DE_UUID){
+        uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
+        context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0;
+    }
+    if (type == DE_DES){
+        context->result = sdp_record_contains_UUID128(element, context->uuid128);
+    }
+    return context->result;
+}
+int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){
+    struct sdp_context_contains_uuid128 context;
+    context.uuid128 = uuid128;
+    context.result = 0;
+    de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context);
+    return context.result;
+}
+    
+// MARK: ServiceRecord matches SearchServicePattern
+// if UUID in searchServicePattern is not found in record => false
+// context { result, record }
+struct sdp_context_match_pattern {
+    uint8_t * record;
+    int result;
+};
+int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context;
+    uint8_t normalizedUUID[16];
+    uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
+    if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){
+        context->result = 0;
+        return 1;
+    }
+    return 0;
+}
+int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){
+    struct sdp_context_match_pattern context;
+    context.record = record;
+    context.result = 1;
+    de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context);
+    return context.result;
+}
+
+// MARK: Dump DataElement
+// context { indent }
+static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){
+    int indent = *(int*) my_context;
+    int i;
+    for (i=0; i<indent;i++) printf("    ");
+    int pos     = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos);
+    if (de_type == DE_DES) {
+		printf("\n");
+        indent++;
+        de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent);
+    } else if (de_type == DE_UUID && de_size == DE_SIZE_128) {
+        printf(", value: ");
+        printUUID(element+1);
+        printf("\n");
+    } else if (de_type == DE_STRING) {
+        int len = 0;
+        switch (de_size){
+            case DE_SIZE_VAR_8:
+                len = element[1];
+                break;
+            case DE_SIZE_VAR_16:
+                len = READ_NET_16(element, 1);
+                break;
+            default:
+                break;
+        }
+        printf("len %u (0x%02x)\n", len, len);
+        hexdump(&element[pos], len);
+    } else {
+        uint32_t value = 0;
+        switch (de_size) {
+            case DE_SIZE_8:
+                if (de_type != DE_NIL){
+                    value = element[pos];
+                }
+                break;
+            case DE_SIZE_16:
+				value = READ_NET_16(element,pos);
+                break;
+            case DE_SIZE_32:
+				value = READ_NET_32(element,pos);
+                break;
+            default:
+                break;
+        }
+        printf(", value: 0x%08" PRIx32 "\n", value);
+    }
+    return 0;
+}
+
+void de_dump_data_element(uint8_t * record){
+    int indent = 0;
+    // hack to get root DES, too.
+    de_type_t type = de_get_element_type(record);
+    de_size_t size = de_get_size_type(record);
+    de_traversal_dump_data(record, type, size, (void*) &indent);
+}
+
+void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){
+	
+	uint8_t* attribute;
+	de_create_sequence(service);
+    
+    // 0x0000 "Service Record Handle"
+	de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
+	de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
+    
+	// 0x0001 "Service Class ID List"
+	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
+	attribute = de_push_sequence(service);
+	{
+		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1101 );
+	}
+	de_pop_sequence(service, attribute);
+	
+	// 0x0004 "Protocol Descriptor List"
+	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
+	attribute = de_push_sequence(service);
+	{
+		uint8_t* l2cpProtocol = de_push_sequence(attribute);
+		{
+			de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, 0x0100);
+		}
+		de_pop_sequence(attribute, l2cpProtocol);
+		
+		uint8_t* rfcomm = de_push_sequence(attribute);
+		{
+			de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, 0x0003);  // rfcomm_service
+			de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  service_id);  // rfcomm channel
+		}
+		de_pop_sequence(attribute, rfcomm);
+	}
+	de_pop_sequence(service, attribute);
+	
+	// 0x0005 "Public Browse Group"
+	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
+	attribute = de_push_sequence(service);
+	{
+		de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1002 );
+	}
+	de_pop_sequence(service, attribute);
+	
+	// 0x0006
+	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList);
+	attribute = de_push_sequence(service);
+	{
+		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
+		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
+		de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
+	}
+	de_pop_sequence(service, attribute);
+	
+	// 0x0009 "Bluetooth Profile Descriptor List"
+	de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
+	attribute = de_push_sequence(service);
+	{
+		uint8_t *sppProfile = de_push_sequence(attribute);
+		{
+			de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, 0x1101);
+			de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0100);
+		}
+		de_pop_sequence(attribute, sppProfile);
+	}
+	de_pop_sequence(service, attribute);
+	
+	// 0x0100 "ServiceName"
+	de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
+	de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/utils.c	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/SomeRandomBloke/code/FatFileSystem/#5baba5d5b728
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/led_counter.cpp	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,56 @@
+#if 0
+//*****************************************************************************
+//
+// led_counter demo - uses the BTstack run loop to blink an LED
+//
+//*****************************************************************************
+#include "mbed.h"
+#include <btstack/run_loop.h>
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2);
+
+#define HEARTBEAT_PERIOD_MS 1000
+
+static void  heartbeat_handler(struct timer *ts){
+
+    // increment counter
+    static int counter = 0;
+    char lineBuffer[30];
+    sprintf(lineBuffer, "BTstack counter %04u\n\r", ++counter);
+    printf(lineBuffer);
+    
+    // toggle LED
+    led2 = !led2;
+    
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+} 
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    printf("%s\n", __FILE__);
+
+    // init LEDs
+    led1 = led2 = 1;
+    
+    /// GET STARTED with BTstack ///
+    run_loop_init(RUN_LOOP_EMBEDDED);
+        
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    printf("Run...\n\r");
+
+    // go!
+    run_loop_execute();    
+    
+    // happy compiler!
+    return 0;
+}
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jun 26 14:27:45 2012 +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/mouse_demo.cpp	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,118 @@
+#if 0
+/* mouse_demo.cpp */
+#include "mbed.h"
+#include <btstack/run_loop.h>
+#include <btstack/hci_cmds.h>
+#include "hci.h"
+#include "l2cap.h"
+#include "debug.h"
+#include "bd_addr.h"  // class bd_addr
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2), led3(LED3);
+
+#define INQUIRY_INTERVAL 15
+
+bd_addr addr;
+
+static void hid_process_packet(uint8_t* report, int size)
+{
+    if (report[0] == 0xa1 && report[1] == 0x02) {
+        led1 = report[2] & 0x01; // left
+        led2 = report[2] & 0x02; // right
+        led3 = report[2] & 0x04; // center
+    }
+    hexdump(report, size);
+}
+
+static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    
+    if (packet_type == HCI_EVENT_PACKET && packet[0] == L2CAP_EVENT_CHANNEL_OPENED){
+        if (packet[2]) {
+            log_info("Connection failed\n");
+            return;
+        }
+        log_info("Connected\n");
+    }
+    if (packet_type == L2CAP_DATA_PACKET){
+        // handle input
+        log_info("HID report, size %u\n", size);
+        hid_process_packet(packet, size);
+    }
+}
+
+static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    if (packet_type == HCI_EVENT_PACKET) {
+        switch (packet[0]) {
+            case BTSTACK_EVENT_STATE:
+                // bt stack activated, get started - set local name
+                if (packet[2] == HCI_STATE_WORKING) {
+                    hci_send_cmd(&hci_write_authentication_enable, 1);
+                }
+                break;
+                    
+            case HCI_EVENT_INQUIRY_RESULT:
+                // ignore none mouses
+                if ((packet[12] & 0x80) != 0x80 || packet[13] != 0x25) break;
+                addr.data(&packet[3]);
+                log_info("Mouse addr: %s\n", addr.to_str());
+                hci_send_cmd(&hci_inquiry_cancel);
+                break;
+                    
+            case HCI_EVENT_INQUIRY_COMPLETE:
+                log_info("No mouse found :(\n");
+                break;
+                
+            case HCI_EVENT_LINK_KEY_REQUEST:
+                // deny link key request
+                hci_send_cmd(&hci_link_key_request_negative_reply, addr.data());
+                break;
+                    
+            case HCI_EVENT_PIN_CODE_REQUEST:
+                // inform about pin code request
+                log_info("Enter 0000\n");
+                hci_send_cmd(&hci_pin_code_request_reply, addr.data(), 4, "0000");
+                break;
+                    
+            case HCI_EVENT_COMMAND_COMPLETE:
+                if (COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable)){
+                    log_info("Inquiry\n");
+                    hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
+                }
+                if (COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel) ) {
+                    // inq successfully cancelled
+                    log_info("Connecting\n");
+                    l2cap_create_channel_internal(NULL, l2cap_packet_handler, addr.data(), PSM_HID_INTERRUPT, 150);
+                }
+                break;
+        }
+    }
+}
+
+int main(void){
+    pc.baud(921600);
+    log_info("%s\n", __FILE__);
+
+    // init LEDs
+    led1 = led2 = led3 = 1;
+    
+    // GET STARTED
+    run_loop_init(RUN_LOOP_EMBEDDED);
+
+    // init HCI
+    hci_transport_t* transport = hci_transport_usb_instance();
+    remote_device_db_t* remote_db = (remote_device_db_t *)&remote_device_db_memory;
+    hci_init(transport, NULL, NULL, remote_db);
+
+    // init L2CAP
+    l2cap_init();
+    l2cap_register_packet_handler(packet_handler);
+
+    // turn on!, send RESET command
+    hci_power_control(HCI_POWER_ON);
+            
+    // go!
+    run_loop_execute();    
+    
+    return 0;
+}
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc/msc.cpp	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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/spp_counter.cpp	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,182 @@
+#if 0
+//*****************************************************************************
+//
+// spp_counter demo - it provides a SPP and sends a counter every second
+//
+// it doesn't use the LCD to get down to a minimal memory footpring
+//
+//*****************************************************************************
+#include "mbed.h"
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/sdp_util.h>
+
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "rfcomm.h"
+#include "sdp.h"
+#include "config.h"
+#include "debug.h"
+#include "bd_addr.h"  // class bd_addr
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2);
+
+#define HEARTBEAT_PERIOD_MS 1000
+
+static uint8_t   rfcomm_channel_nr = 1;
+static uint16_t  rfcomm_channel_id = 0;
+static uint8_t   spp_service_buffer[128];
+
+// Bluetooth logic
+static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    uint8_t   rfcomm_channel_nr;
+    uint16_t  mtu;
+    
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            switch (packet[0]) {
+                    
+                case BTSTACK_EVENT_STATE:
+                    // bt stack activated, get started - set local name
+                    if (packet[2] == HCI_STATE_WORKING) {
+                        hci_send_cmd(&hci_write_local_name, "mbed-Demo");
+                    }
+                    break;
+                
+                case HCI_EVENT_COMMAND_COMPLETE:
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
+                        bt_flip_addr(event_addr, &packet[6]);
+                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
+                        hci_discoverable_control(1);
+                        break;
+                    }
+                    break;
+
+                case HCI_EVENT_LINK_KEY_REQUEST:
+                    // deny link key request
+                    log_info("Link key request\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
+                    break;
+                    
+                case HCI_EVENT_PIN_CODE_REQUEST:
+                    // inform about pin code request
+                    log_info("Pin code request - using '0000'\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
+                    break;
+                
+                case RFCOMM_EVENT_INCOMING_CONNECTION:
+                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+                    bt_flip_addr(event_addr, &packet[2]); 
+                    rfcomm_channel_nr = packet[8];
+                    rfcomm_channel_id = READ_BT_16(packet, 9);
+                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
+                    rfcomm_accept_connection_internal(rfcomm_channel_id);
+                    break;
+                    
+                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
+                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
+                    if (packet[2]) {
+                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
+                    } else {
+                        rfcomm_channel_id = READ_BT_16(packet, 12);
+                        mtu = READ_BT_16(packet, 14);
+                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
+                    }
+                    break;
+                    
+                case RFCOMM_EVENT_CHANNEL_CLOSED:
+                    rfcomm_channel_id = 0;
+                    break;
+                
+                default:
+                    break;
+            }
+            break;
+                        
+        default:
+            break;
+    }
+}
+
+static void  heartbeat_handler(struct timer *ts){
+
+    if (rfcomm_channel_id){
+        static int counter = 0;
+        char lineBuffer[32];
+        snprintf(lineBuffer, sizeof(lineBuffer), "counter %04u\n\r", ++counter);
+        log_info("%s\n", lineBuffer);
+        int err = rfcomm_send_internal(rfcomm_channel_id, (uint8_t*) lineBuffer, strlen(lineBuffer));
+        if (err) {
+            log_info("rfcomm_send_internal -> error %d", err);
+        }
+    }
+    
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+    led2 = !led2;
+} 
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    log_info("%s\n", __FILE__);
+
+
+    // init LEDs
+    led1 = led2 = 1;
+    
+    /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    
+    // init HCI
+    hci_transport_t    * transport = hci_transport_usb_instance();
+    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
+    hci_init(transport, NULL, NULL, remote_db);
+    
+    // init L2CAP
+    l2cap_init();
+    l2cap_register_packet_handler(packet_handler);
+    
+    // init RFCOMM
+    rfcomm_init();
+    rfcomm_register_packet_handler(packet_handler);
+    rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100);  // reserved channel, mtu=100
+
+    // init SDP, create record for SPP and register with SDP
+    sdp_init();
+    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
+    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
+    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
+    log_info("SDP service buffer size: %u\n", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
+    sdp_register_service_internal(NULL, service_record_item);
+    
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    log_info("Run...\n\r");
+
+     // turn on!
+    hci_power_control(HCI_POWER_ON);
+
+    // go!
+    run_loop_execute();    
+    
+    // happy compiler!
+    return 0;
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spp_demo.cpp	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,172 @@
+#if 1
+/*
+ * spp_demo
+ */
+#include "mbed.h"
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/sdp_util.h>
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "rfcomm.h"
+#include "sdp.h"
+#include "config.h"
+#include "debug.h"
+#include "bd_addr.h"  // class bd_addr
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2), led3(LED3);
+
+#define HEARTBEAT_PERIOD_MS 500
+
+static uint8_t   rfcomm_channel_nr = 1;
+static uint16_t  rfcomm_channel_id = 0;
+static uint8_t   spp_service_buffer[128];
+
+// Bluetooth logic
+static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    uint8_t   rfcomm_channel_nr;
+    uint16_t  mtu;
+    int err;
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            switch (packet[0]) {
+                    
+                case BTSTACK_EVENT_STATE:
+                    // bt stack activated, get started - set local name
+                    if (packet[2] == HCI_STATE_WORKING) {
+                        hci_send_cmd(&hci_write_local_name, "mbed");
+                    }
+                    break;
+                
+                case HCI_EVENT_COMMAND_COMPLETE:
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
+                        bt_flip_addr(event_addr, &packet[6]);
+                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
+                        hci_discoverable_control(1);
+                        break;
+                    }
+                    break;
+
+                case HCI_EVENT_LINK_KEY_REQUEST:
+                    // deny link key request
+                    log_info("Link key request\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
+                    break;
+                    
+                case HCI_EVENT_PIN_CODE_REQUEST:
+                    // inform about pin code request
+                    log_info("Pin code request - using '0000'\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
+                    break;
+                
+                case RFCOMM_EVENT_INCOMING_CONNECTION:
+                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+                    bt_flip_addr(event_addr, &packet[2]); 
+                    rfcomm_channel_nr = packet[8];
+                    rfcomm_channel_id = READ_BT_16(packet, 9);
+                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
+                    rfcomm_accept_connection_internal(rfcomm_channel_id);
+                    break;
+                    
+                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
+                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
+                    if (packet[2]) {
+                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
+                    } else {
+                        rfcomm_channel_id = READ_BT_16(packet, 12);
+                        mtu = READ_BT_16(packet, 14);
+                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
+                    }
+                    break;
+                    
+                case RFCOMM_EVENT_CHANNEL_CLOSED:
+                    rfcomm_channel_id = 0;
+                    break;
+                
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_DATA_PACKET:
+            // loopback
+            if (rfcomm_channel_id) {
+                err = rfcomm_send_internal(rfcomm_channel_id, packet, size);
+                if (err) {
+                    log_info("rfcomm_send_internal -> error %d", err);
+                }
+            }
+            led3 = !led3;
+            break;
+        default:
+            break;
+    }
+}
+
+static void  heartbeat_handler(struct timer *ts){
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+    led2 = !led2;
+} 
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    log_info("%s\n", __FILE__);
+
+    // init LEDs
+    led1 = led2 = led3 = 1;
+    
+    /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    
+    // init HCI
+    hci_transport_t* transport = hci_transport_usb_instance();
+    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
+    hci_init(transport, NULL, NULL, remote_db);
+    
+    // init L2CAP
+    l2cap_init();
+    l2cap_register_packet_handler(packet_handler);
+    
+    // init RFCOMM
+    rfcomm_init();
+    rfcomm_register_packet_handler(packet_handler);
+    rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100);  // reserved channel, mtu=100
+
+    // init SDP, create record for SPP and register with SDP
+    sdp_init();
+    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
+    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
+    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "loopback");
+    log_info("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
+    sdp_register_service_internal(NULL, service_record_item);
+    
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    log_info("SPP loopback demo...\n\r");
+
+     // turn on!
+    hci_power_control(HCI_POWER_ON);
+
+    // go!
+    run_loop_execute();    
+
+    return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spp_flowcontrol.cpp	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,178 @@
+#if 0
+//*****************************************************************************
+//
+// spp_counter demo - it provides a SPP and sends a counter every second
+//
+// it doesn't use the LCD to get down to a minimal memory footpring
+//
+//*****************************************************************************
+#include "mbed.h"
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/sdp_util.h>
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "rfcomm.h"
+#include "sdp.h"
+#include "config.h"
+#include "debug.h"
+#include "bd_addr.h"  // class bd_addr
+
+Serial pc(USBTX, USBRX);
+DigitalOut led1(LED1), led2(LED2);
+
+#define HEARTBEAT_PERIOD_MS 500
+
+static uint8_t   rfcomm_channel_nr = 1;
+static uint16_t  rfcomm_channel_id = 0;
+static uint8_t   rfcomm_send_credit = 0;
+static uint8_t   spp_service_buffer[128];
+
+// Bluetooth logic
+static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    uint8_t   rfcomm_channel_nr;
+    uint16_t  mtu;
+    
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            switch (packet[0]) {
+                    
+                case BTSTACK_EVENT_STATE:
+                    // bt stack activated, get started - set local name
+                    if (packet[2] == HCI_STATE_WORKING) {
+                        hci_send_cmd(&hci_write_local_name, "mbed-Demo");
+                    }
+                    break;
+                
+                case HCI_EVENT_COMMAND_COMPLETE:
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
+                        bt_flip_addr(event_addr, &packet[6]);
+                        log_info("BD-ADDR: %s\n\r", bd_addr_to_str(event_addr));
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
+                        hci_discoverable_control(1);
+                        break;
+                    }
+                    break;
+
+                case HCI_EVENT_LINK_KEY_REQUEST:
+                    // deny link key request
+                    log_info("Link key request\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
+                    break;
+                    
+                case HCI_EVENT_PIN_CODE_REQUEST:
+                    // inform about pin code request
+                    log_info("Pin code request - using '0000'\n\r");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
+                    break;
+                
+                case RFCOMM_EVENT_INCOMING_CONNECTION:
+                    // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+                    bt_flip_addr(event_addr, &packet[2]); 
+                    rfcomm_channel_nr = packet[8];
+                    rfcomm_channel_id = READ_BT_16(packet, 9);
+                    log_info("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(event_addr));
+                    rfcomm_accept_connection_internal(rfcomm_channel_id);
+                    break;
+                    
+                case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
+                    // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
+                    if (packet[2]) {
+                        log_info("RFCOMM channel open failed, status %u\n\r", packet[2]);
+                    } else {
+                        rfcomm_channel_id = READ_BT_16(packet, 12);
+                        mtu = READ_BT_16(packet, 14);
+                        log_info("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
+                    }
+                    break;
+                    
+                case RFCOMM_EVENT_CHANNEL_CLOSED:
+                    rfcomm_channel_id = 0;
+                    break;
+                
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_DATA_PACKET:
+            // hack: truncate data (we know that the packet is at least on byte bigger
+            packet[size] = 0;
+            puts( (const char *) packet);
+            rfcomm_send_credit = 1;
+        default:
+            break;
+    }
+}
+
+static void  heartbeat_handler(struct timer *ts){
+    if (rfcomm_send_credit){
+        rfcomm_grant_credits(rfcomm_channel_id, 1);
+        rfcomm_send_credit = 0;
+    }
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+    led2 = !led2;
+} 
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    log_info("%s\n", __FILE__);
+
+    // init LEDs
+    led1 = led2 = 1;
+    
+    /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    
+    // init HCI
+    hci_transport_t* transport = hci_transport_usb_instance();
+    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
+    hci_init(transport, NULL, NULL, remote_db);
+    
+    // init L2CAP
+    l2cap_init();
+    l2cap_register_packet_handler(packet_handler);
+    
+    // init RFCOMM
+    rfcomm_init();
+    rfcomm_register_packet_handler(packet_handler);
+    rfcomm_register_service_with_initial_credits_internal(NULL, rfcomm_channel_nr, 100, 1);  // reserved channel, mtu=100, 1 credit
+
+    // init SDP, create record for SPP and register with SDP
+    sdp_init();
+    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
+    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
+    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "SPP Counter");
+    log_info("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
+    sdp_register_service_internal(NULL, service_record_item);
+    
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    
+    log_info("SPP FlowControl Demo: simulates processing on received data...\n\r");
+
+     // turn on!
+    hci_power_control(HCI_POWER_ON);
+
+    // go!
+    run_loop_execute();    
+    
+    // happy compiler!
+    return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb/UsbBaseClass.cpp	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +0000
@@ -0,0 +1,34 @@
+#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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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	Tue Jun 26 14:27:45 2012 +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();
+    }
+}
+