BTstack for Nucleo F401RE/FRDM-KL46Z example program

Dependencies:   F401RE-USBHost mbed

The usage is the same as KL46Z-BTstack_example.
使い方はKL46Z-BTstack_exampleと同じです。
/media/uploads/va009039/f401re-btstack.jpg

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Mon Jun 09 09:03:25 2014 +0000
Commit message:
first commit

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
F401RE-USBHost.lib Show annotated file Show diff for this revision Revisions of this file
KL46Z-USBHostBTstack/USBHostBTstack.cpp Show annotated file Show diff for this revision Revisions of this file
KL46Z-USBHostBTstack/USBHostBTstack.h Show annotated file Show diff for this revision Revisions of this file
main.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
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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/bt_control.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  bt_control.h
+ *
+ *  BT Control API -- allows BT Daemon to initialize and control differnt hardware
+ *
+ *  Created by Matthias Ringwald on 5/19/09.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    POWER_WILL_SLEEP = 1,
+    POWER_WILL_WAKE_UP
+} POWER_NOTIFICATION_t;
+
+typedef struct {
+    int          (*on)   (void *config);  // <-- turn BT module on and configure
+    int          (*off)  (void *config);  // <-- turn BT module off
+    int          (*sleep)(void *config);  // <-- put BT module to sleep    - only to be called after ON
+    int          (*wake) (void *config);  // <-- wake BT module from sleep - only to be called after SLEEP
+    int          (*valid)(void *config);  // <-- test if hardware can be supported
+    const char * (*name) (void *config);  // <-- return hardware name
+
+    /** support for UART baud rate changes - cmd has to be stored in hci_cmd_buffer
+     * @return have command
+     */
+    int          (*baudrate_cmd)(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer); 
+    
+    /** support custom init sequences after RESET command - cmd has to be stored in hci_cmd_buffer
+      * @return have command
+      */
+    int          (*next_cmd)(void *config, uint8_t * hci_cmd_buffer); 
+
+    void         (*register_for_power_notifications)(void (*cb)(POWER_NOTIFICATION_t event));
+
+    void         (*hw_error)(void); 
+} bt_control_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/btstack.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  btstack.h
+ *
+ *  Created by Matthias Ringwald on 7/1/09.
+ *
+ *  BTstack client API
+ *  
+ */
+
+#pragma once
+
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/utils.h>
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+// Default TCP port for BTstack daemon
+#define BTSTACK_PORT            13333
+
+// UNIX domain socket for BTstack */
+#define BTSTACK_UNIX            "/tmp/BTstack"
+
+// packet handler
+typedef void (*btstack_packet_handler_t) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+
+// optional: if called before bt_open, TCP socket is used instead of local unix socket
+//           note: address is not copied and must be valid during bt_open
+void bt_use_tcp(const char * address, uint16_t port); 
+
+// init BTstack library
+int bt_open(void);
+
+// stop using BTstack library
+int bt_close(void);
+
+// send hci cmd packet
+int bt_send_cmd(const hci_cmd_t *cmd, ...);
+
+// register packet handler -- channel only valid for l2cap and rfcomm packets
+// @returns old packet handler
+btstack_packet_handler_t bt_register_packet_handler(btstack_packet_handler_t handler);
+
+void bt_send_acl(uint8_t * data, uint16_t len);
+
+void bt_send_l2cap(uint16_t local_cid, uint8_t *data, uint16_t len);
+void bt_send_rfcomm(uint16_t rfcom_cid, uint8_t *data, uint16_t len);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hal_cpu.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,49 @@
+/*
+ * 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
+ */
+#if defined __cplusplus
+extern "C" {
+#endif
+ 
+void hal_cpu_disable_irqs(void);
+void hal_cpu_enable_irqs(void);
+void hal_cpu_enable_irqs_and_sleep(void);
+
+#if defined __cplusplus
+}
+#endif
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hal_tick.h	Mon Jun 09 09:03:25 2014 +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_tick.h
+ *
+ *  Hardware abstraction layer for periodic ticks
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+void hal_tick_init(void);
+void hal_tick_set_handler(void (*tick_handler)(void));
+int  hal_tick_get_tick_period_in_ms(void);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/hci_cmds.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hci_cmds.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+/**
+ * packet types - used in BTstack and over the H4 UART interface
+ */
+#define HCI_COMMAND_DATA_PACKET	0x01
+#define HCI_ACL_DATA_PACKET	    0x02
+#define HCI_SCO_DATA_PACKET	    0x03
+#define HCI_EVENT_PACKET	    0x04
+
+// extension for client/server communication
+#define DAEMON_EVENT_PACKET     0x05
+    
+// L2CAP data
+#define L2CAP_DATA_PACKET       0x06
+
+// RFCOMM data
+#define RFCOMM_DATA_PACKET      0x07
+
+// Attribute protocol data
+#define ATT_DATA_PACKET         0x08
+
+// Security Manager protocol data
+#define SM_DATA_PACKET          0x09
+    
+// debug log messages
+#define LOG_MESSAGE_PACKET      0xfc
+
+    
+// Fixed PSM numbers
+#define PSM_SDP    0x01
+#define PSM_RFCOMM 0x03
+#define PSM_HID_CONTROL 0x11
+#define PSM_HID_INTERRUPT 0x13
+
+// Events from host controller to host
+#define HCI_EVENT_INQUIRY_COMPLETE				           0x01
+#define HCI_EVENT_INQUIRY_RESULT				           0x02
+#define HCI_EVENT_CONNECTION_COMPLETE			           0x03
+#define HCI_EVENT_CONNECTION_REQUEST			           0x04
+#define HCI_EVENT_DISCONNECTION_COMPLETE		      	   0x05
+#define HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT            0x06
+#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE	           0x07
+#define HCI_EVENT_ENCRYPTION_CHANGE                        0x08
+#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE      0x09
+#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE                 0x0A
+#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE  0x0B
+#define HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
+#define HCI_EVENT_QOS_SETUP_COMPLETE			           0x0D
+#define HCI_EVENT_COMMAND_COMPLETE				           0x0E
+#define HCI_EVENT_COMMAND_STATUS				           0x0F
+#define HCI_EVENT_HARDWARE_ERROR                           0x10
+#define HCI_EVENT_FLUSH_OCCURED                            0x11
+#define HCI_EVENT_ROLE_CHANGE				               0x12
+#define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS	      	   0x13
+#define HCI_EVENT_MODE_CHANGE_EVENT                        0x14
+#define HCI_EVENT_RETURN_LINK_KEYS                         0x15
+#define HCI_EVENT_PIN_CODE_REQUEST                         0x16
+#define HCI_EVENT_LINK_KEY_REQUEST                         0x17
+#define HCI_EVENT_LINK_KEY_NOTIFICATION                    0x18
+#define HCI_EVENT_DATA_BUFFER_OVERFLOW                     0x1A
+#define HCI_EVENT_MAX_SLOTS_CHANGED			               0x1B
+#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE               0x1C
+#define HCI_EVENT_PACKET_TYPE_CHANGED                      0x1D
+#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI		      	   0x22
+#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE                0x2F
+#define HCI_EVENT_LE_META                                  0x3E
+#define HCI_EVENT_VENDOR_SPECIFIC				           0xFF
+
+#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE                0x01
+#define HCI_SUBEVENT_LE_ADVERTISING_REPORT                 0x02
+#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE         0x03
+#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
+#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST              0x05
+    
+// last used HCI_EVENT in 2.1 is 0x3d
+
+// events 0x50-0x5f are used internally
+
+// BTSTACK DAEMON EVENTS
+
+// events from BTstack for application/client lib
+#define BTSTACK_EVENT_STATE                                0x60
+
+// data: event(8), len(8), nr hci connections
+#define BTSTACK_EVENT_NR_CONNECTIONS_CHANGED               0x61
+
+// data: none
+#define BTSTACK_EVENT_POWERON_FAILED                       0x62
+
+// data: majot (8), minor (8), revision(16)
+#define BTSTACK_EVENT_VERSION	        				   0x63
+
+// data: system bluetooth on/off (bool)
+#define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED			   0x64
+
+// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes)
+#define BTSTACK_EVENT_REMOTE_NAME_CACHED	     		   0x65
+
+// data: discoverable enabled (bool)
+#define BTSTACK_EVENT_DISCOVERABLE_ENABLED			       0x66
+
+// L2CAP EVENTS
+	
+// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 
+#define L2CAP_EVENT_CHANNEL_OPENED                         0x70
+
+// data: event (8), len(8), channel (16)
+#define L2CAP_EVENT_CHANNEL_CLOSED                         0x71
+
+// data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) 
+#define L2CAP_EVENT_INCOMING_CONNECTION					   0x72
+
+// data: event(8), len(8), handle(16)
+#define L2CAP_EVENT_TIMEOUT_CHECK                          0x73
+
+// data: event(8), len(8), local_cid(16), credits(8)
+#define L2CAP_EVENT_CREDITS								   0x74
+
+// data: event(8), len(8), status (8), psm (16)
+#define L2CAP_EVENT_SERVICE_REGISTERED                     0x75
+
+
+// RFCOMM EVENTS
+	
+// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
+#define RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE                 0x80
+	
+// data: event(8), len(8), rfcomm_cid(16)
+#define RFCOMM_EVENT_CHANNEL_CLOSED                        0x81
+	
+// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+#define RFCOMM_EVENT_INCOMING_CONNECTION                   0x82
+	
+// data: event (8), len(8), rfcommid (16), ...
+#define RFCOMM_EVENT_REMOTE_LINE_STATUS                    0x83
+	
+// data: event(8), len(8), rfcomm_cid(16), credits(8)
+#define RFCOMM_EVENT_CREDITS			                   0x84
+	
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_SERVICE_REGISTERED                    0x85
+    
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_PERSISTENT_CHANNEL                    0x86
+    
+    
+// data: event(8), len(8), status(8), service_record_handle(32)
+#define SDP_SERVICE_REGISTERED                             0x90
+
+	
+// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors
+
+#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED              0x50
+#define BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH		   0x51
+#define BTSTACK_ACTIVATION_POWERON_FAILED       		   0x52
+#define BTSTACK_ACTIVATION_FAILED_UNKNOWN       		   0x53
+#define BTSTACK_NOT_ACTIVATED							   0x54
+#define BTSTACK_BUSY									   0x55
+#define BTSTACK_MEMORY_ALLOC_FAILED                        0x56
+#define BTSTACK_ACL_BUFFERS_FULL                           0x57
+
+// l2cap errors - enumeration by the command that created them
+#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60
+#define L2CAP_COMMAND_REJECT_REASON_SIGNALING_MTU_EXCEEDED 0x61
+#define L2CAP_COMMAND_REJECT_REASON_INVALID_CID_IN_REQUEST 0x62
+
+#define L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL        0x63
+#define L2CAP_CONNECTION_RESPONSE_RESULT_PENDING           0x64
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_PSM       0x65
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY  0x66
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES 0x65
+
+#define L2CAP_CONFIG_RESPONSE_RESULT_SUCCESSFUL            0x66
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNACCEPTABLE_PARAMS   0x67
+#define L2CAP_CONFIG_RESPONSE_RESULT_REJECTED              0x68
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS       0x69
+#define L2CAP_SERVICE_ALREADY_REGISTERED                   0x6a
+    
+#define RFCOMM_MULTIPLEXER_STOPPED                         0x70
+#define RFCOMM_CHANNEL_ALREADY_REGISTERED                  0x71
+#define RFCOMM_NO_OUTGOING_CREDITS                         0x72
+
+#define SDP_HANDLE_ALREADY_REGISTERED                      0x80
+ 
+/**
+ * Default INQ Mode
+ */
+#define HCI_INQUIRY_LAP 0x9E8B33L  // 0x9E8B33: General/Unlimited Inquiry Access Code (GIAC)
+/**
+ *  Hardware state of Bluetooth controller 
+ */
+typedef enum {
+    HCI_POWER_OFF = 0,
+    HCI_POWER_ON,
+	HCI_POWER_SLEEP
+} HCI_POWER_MODE;
+
+/**
+ * State of BTstack 
+ */
+typedef enum {
+    HCI_STATE_OFF = 0,
+    HCI_STATE_INITIALIZING,
+    HCI_STATE_WORKING,
+    HCI_STATE_HALTING,
+	HCI_STATE_SLEEPING,
+	HCI_STATE_FALLING_ASLEEP
+} HCI_STATE;
+
+/** 
+ * compact HCI Command packet description
+ */
+ typedef struct {
+    uint16_t    opcode;
+    const char *format;
+} hci_cmd_t;
+
+
+// HCI Commands - see hci_cmds.c for info on parameters
+extern const hci_cmd_t btstack_get_state;
+extern const hci_cmd_t btstack_set_power_mode;
+extern const hci_cmd_t btstack_set_acl_capture_mode;
+extern const hci_cmd_t btstack_get_version;
+extern const hci_cmd_t btstack_get_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_discoverable;
+extern const hci_cmd_t btstack_set_bluetooth_enabled;    // only used by btstack config
+	
+extern const hci_cmd_t hci_accept_connection_request;
+extern const hci_cmd_t hci_authentication_requested;
+extern const hci_cmd_t hci_change_connection_link_key;
+extern const hci_cmd_t hci_create_connection;
+extern const hci_cmd_t hci_create_connection_cancel;
+extern const hci_cmd_t hci_delete_stored_link_key;
+extern const hci_cmd_t hci_disconnect;
+extern const hci_cmd_t hci_host_buffer_size;
+extern const hci_cmd_t hci_inquiry;
+extern const hci_cmd_t hci_inquiry_cancel;
+extern const hci_cmd_t hci_link_key_request_negative_reply;
+extern const hci_cmd_t hci_link_key_request_reply;
+extern const hci_cmd_t hci_pin_code_request_reply;
+extern const hci_cmd_t hci_pin_code_request_negative_reply;
+extern const hci_cmd_t hci_qos_setup;
+extern const hci_cmd_t hci_read_bd_addr;
+extern const hci_cmd_t hci_read_buffer_size;
+extern const hci_cmd_t hci_read_le_host_supported;
+extern const hci_cmd_t hci_read_link_policy_settings;
+extern const hci_cmd_t hci_read_link_supervision_timeout;
+extern const hci_cmd_t hci_read_local_supported_features;
+extern const hci_cmd_t hci_read_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_reject_connection_request;
+extern const hci_cmd_t hci_remote_name_request;
+extern const hci_cmd_t hci_remote_name_request_cancel;
+extern const hci_cmd_t hci_reset;
+extern const hci_cmd_t hci_role_discovery;
+extern const hci_cmd_t hci_set_event_mask;
+extern const hci_cmd_t hci_set_connection_encryption;
+extern const hci_cmd_t hci_sniff_mode;
+extern const hci_cmd_t hci_switch_role_command;
+extern const hci_cmd_t hci_write_authentication_enable;
+extern const hci_cmd_t hci_write_class_of_device;
+extern const hci_cmd_t hci_write_extended_inquiry_response;
+extern const hci_cmd_t hci_write_inquiry_mode;
+extern const hci_cmd_t hci_write_le_host_supported;
+extern const hci_cmd_t hci_write_link_policy_settings;
+extern const hci_cmd_t hci_write_link_supervision_timeout;
+extern const hci_cmd_t hci_write_local_name;
+extern const hci_cmd_t hci_write_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_write_page_timeout;
+extern const hci_cmd_t hci_write_scan_enable;
+extern const hci_cmd_t hci_write_simple_pairing_mode;
+
+extern const hci_cmd_t hci_le_add_device_to_whitelist;
+extern const hci_cmd_t hci_le_clear_white_list;
+extern const hci_cmd_t hci_le_connection_update;
+extern const hci_cmd_t hci_le_create_connection;
+extern const hci_cmd_t hci_le_create_connection_cancel;
+extern const hci_cmd_t hci_le_encrypt;
+extern const hci_cmd_t hci_le_long_term_key_negative_reply;
+extern const hci_cmd_t hci_le_long_term_key_request_reply;
+extern const hci_cmd_t hci_le_rand;
+extern const hci_cmd_t hci_le_read_advertising_channel_tx_power;
+extern const hci_cmd_t hci_le_read_buffer_size ;
+extern const hci_cmd_t hci_le_read_channel_map;
+extern const hci_cmd_t hci_le_read_remote_used_features;
+extern const hci_cmd_t hci_le_read_supported_features;
+extern const hci_cmd_t hci_le_read_supported_states;
+extern const hci_cmd_t hci_le_read_white_list_size;
+extern const hci_cmd_t hci_le_receiver_test;
+extern const hci_cmd_t hci_le_remove_device_from_whitelist;
+extern const hci_cmd_t hci_le_set_advertise_enable;
+extern const hci_cmd_t hci_le_set_advertising_data;
+extern const hci_cmd_t hci_le_set_advertising_parameters;
+extern const hci_cmd_t hci_le_set_event_mask;
+extern const hci_cmd_t hci_le_set_host_channel_classification;
+extern const hci_cmd_t hci_le_set_random_address;
+extern const hci_cmd_t hci_le_set_scan_enable;
+extern const hci_cmd_t hci_le_set_scan_parameters;
+extern const hci_cmd_t hci_le_set_scan_response_data;
+extern const hci_cmd_t hci_le_start_encryption;
+extern const hci_cmd_t hci_le_test_end;
+extern const hci_cmd_t hci_le_transmitter_test;
+    
+extern const hci_cmd_t l2cap_accept_connection;
+extern const hci_cmd_t l2cap_create_channel;
+extern const hci_cmd_t l2cap_create_channel_mtu;
+extern const hci_cmd_t l2cap_decline_connection;
+extern const hci_cmd_t l2cap_disconnect;
+extern const hci_cmd_t l2cap_register_service;
+extern const hci_cmd_t l2cap_unregister_service;
+
+extern const hci_cmd_t sdp_register_service_record;
+extern const hci_cmd_t sdp_unregister_service_record;
+
+// accept connection @param bd_addr(48), rfcomm_cid (16)
+extern const hci_cmd_t rfcomm_accept_connection;
+// create rfcomm channel: @param bd_addr(48), channel (8)
+extern const hci_cmd_t rfcomm_create_channel;
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+extern const hci_cmd_t rfcomm_create_channel_with_initial_credits;
+// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
+extern const hci_cmd_t rfcomm_decline_connection;
+// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
+extern const hci_cmd_t rfcomm_disconnect;
+// register rfcomm service: @param channel(8), mtu (16)
+extern const hci_cmd_t rfcomm_register_service;
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
+// unregister rfcomm service, @param service_channel(16)
+extern const hci_cmd_t rfcomm_unregister_service;
+// request persisten rfcomm channel for service name: serive name (char*) 
+extern const hci_cmd_t rfcomm_persistent_channel_for_service;
+    
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/linked_list.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  linked_list.h
+ *
+ *  Created by Matthias Ringwald on 7/13/09.
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+typedef struct linked_item {
+    struct linked_item *next; // <-- next element in list, or NULL
+    void *user_data;          // <-- pointer to struct base
+} linked_item_t;
+
+typedef linked_item_t * linked_list_t;
+
+void linked_item_set_user(linked_item_t *item, void *user_data);        // <-- set user data
+void * linked_item_get_user(linked_item_t *item);                       // <-- get user data
+int  linked_list_empty(linked_list_t * list);
+void linked_list_add(linked_list_t * list, linked_item_t *item);        // <-- add item to list as first element
+void linked_list_add_tail(linked_list_t * list, linked_item_t *item);   // <-- add item to list as last element
+int  linked_list_remove(linked_list_t * list, linked_item_t *item);     // <-- remove item from list
+linked_item_t * linked_list_get_last_item(linked_list_t * list);        // <-- find the last item in the list
+
+void test_linked_list(void);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/memory_pool.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  memory_pool.h
+ *
+ *  @Brief Fixed-size block allocation
+ *
+ *  @Assumption block_size >= sizeof(void *)
+ *  @Assumption size of storage >= count * block_size
+ *
+ *  @Note minimal implementation, no error checking/handling
+ */
+
+#pragma once
+
+typedef void * memory_pool_t;
+
+// initialize memory pool with with given storage, block size and count
+void   memory_pool_create(memory_pool_t *pool, void * storage, int count, int block_size);
+
+// get free block from pool, @returns NULL or pointer to block
+void * memory_pool_get(memory_pool_t *pool);
+
+// return previously reserved block to memory pool
+void   memory_pool_free(memory_pool_t *pool, void * block);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/run_loop.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  run_loop.h
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <btstack/linked_list.h>
+
+#include <stdint.h>
+
+#ifdef HAVE_TIME
+#include <sys/time.h>
+#endif
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+typedef enum {
+	RUN_LOOP_POSIX = 1,
+	RUN_LOOP_COCOA,
+	RUN_LOOP_EMBEDDED
+} RUN_LOOP_TYPE;
+
+typedef struct data_source {
+    linked_item_t item;
+    int  fd;                                 // <-- file descriptor to watch or 0
+    int  (*process)(struct data_source *ds); // <-- do processing
+} data_source_t;
+
+typedef struct timer {
+    linked_item_t item; 
+#ifdef HAVE_TIME
+    struct timeval timeout;                  // <-- next timeout
+#endif
+#ifdef HAVE_TICK
+    uint32_t timeout;                       // timeout in system ticks
+#endif
+    void  (*process)(struct timer *ts);      // <-- do processing
+} timer_source_t;
+
+
+// set timer based on current time
+void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms);
+
+// add/remove timer_source
+void run_loop_add_timer(timer_source_t *timer); 
+int  run_loop_remove_timer(timer_source_t *timer);
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type);
+
+// add/remove data_source
+void run_loop_add_data_source(data_source_t *dataSource);
+int  run_loop_remove_data_source(data_source_t *dataSource);
+
+
+// execute configured run_loop
+void run_loop_execute(void);
+
+// hack to fix HCI timer handling
+#ifdef HAVE_TICK
+uint32_t embedded_get_ticks(void);
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms);
+#endif
+#ifdef EMBEDDED
+void     embedded_trigger(void);    
+#endif
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/sdp_util.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  sdp_util.h
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+	
+typedef enum {
+    DE_NIL = 0,
+    DE_UINT,
+    DE_INT,
+    DE_UUID,
+    DE_STRING,
+    DE_BOOL,
+    DE_DES,
+    DE_DEA,
+    DE_URL
+} de_type_t;
+
+typedef enum {
+    DE_SIZE_8 = 0,
+    DE_SIZE_16,
+    DE_SIZE_32,
+    DE_SIZE_64,
+    DE_SIZE_128,
+    DE_SIZE_VAR_8,
+    DE_SIZE_VAR_16,
+    DE_SIZE_VAR_32
+} de_size_t;
+
+// UNIVERSAL ATTRIBUTE DEFINITIONS
+#define SDP_ServiceRecordHandle     0x0000
+#define SDP_ServiceClassIDList      0x0001
+#define SDP_ServiceRecordState      0x0002
+#define SDP_ServiceID               0x0003
+#define SDP_ProtocolDescriptorList  0x0004
+#define SDP_BrowseGroupList		    0x0005
+#define SDP_LanguageBaseAttributeIDList 0x0006
+#define SDP_ServiceInfoTimeToLive	0x0007
+#define SDP_ServiceAvailability		0x0008
+#define SDP_BluetoothProfileDescriptorList 0x0009
+#define SDP_DocumentationURL		0x000a
+#define SDP_ClientExecutableURL     0x000b
+#define SDP_IconURL                 0x000c
+#define SDP_AdditionalProtocolDescriptorList 0x000d
+#define SDP_SupportedFormatsList    0x0303
+
+// SERVICE CLASSES
+#define SDP_OBEXObjectPush    0x1105
+#define SDP_OBEXFileTransfer  0x1106
+#define SDP_PublicBrowseGroup 0x1002
+
+// PROTOCOLS
+#define SDP_SDPProtocol       0x0001
+#define SDP_UDPProtocol       0x0002
+#define SDP_RFCOMMProtocol    0x0003
+#define SDP_OBEXProtocol      0x0008
+#define SDP_L2CAPProtocol     0x0100
+
+// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
+#define SDP_Offest_ServiceName      0x0000
+#define SDP_Offest_ServiceDescription 0x0001
+#define SDP_Offest_ProviderName     0x0002
+
+// OBEX
+#define SDP_vCard_2_1       0x01
+#define SDP_vCard_3_0       0x02
+#define SDP_vCal_1_0        0x03
+#define SDP_iCal_2_0        0x04
+#define SDP_vNote           0x05
+#define SDP_vMessage        0x06
+#define SDP_OBEXFileTypeAny 0xFF
+
+// MARK: DateElement
+void de_dump_data_element(uint8_t * record);
+int de_get_len(uint8_t *header);
+de_size_t de_get_size_type(uint8_t *header);
+de_type_t de_get_element_type(uint8_t *header);
+int de_get_header_size(uint8_t * header);
+void de_create_sequence(uint8_t *header);
+void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
+uint8_t * de_push_sequence(uint8_t *header);
+void de_pop_sequence(uint8_t * parent, uint8_t * child);
+void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
+void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
+
+int de_get_data_size(uint8_t * header);
+void de_add_uuid128(uint8_t * seq, uint8_t * uuid);
+
+// MARK: SDP
+uint16_t  sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
+uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
+uint8_t   sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
+int       sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
+int       spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
+int       sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);  
+
+void      sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack/utils.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  utils.h
+ *
+ *  General utility functions
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/**
+ * @brief hci connection handle type
+ */
+typedef uint16_t hci_con_handle_t;
+
+/**
+ * @brief Length of a bluetooth device address.
+ */
+#define BD_ADDR_LEN 6
+typedef uint8_t bd_addr_t[BD_ADDR_LEN];
+
+/**
+ * @brief The link key type
+ */
+#define LINK_KEY_LEN 16
+typedef uint8_t link_key_t[LINK_KEY_LEN]; 
+
+/**
+ * @brief The device name type
+ */
+#define DEVICE_NAME_LEN 248
+typedef uint8_t device_name_t[DEVICE_NAME_LEN+1]; 
+	
+	
+// helper for BT little endian format
+#define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
+#define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16))
+#define READ_BT_32( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16) | (((uint32_t) buffer[pos+3])) << 24)
+
+// helper for SDP big endian format
+#define READ_NET_16( buffer, pos) ( ((uint16_t) buffer[pos+1]) | (((uint16_t)buffer[pos  ]) << 8))
+#define READ_NET_32( buffer, pos) ( ((uint32_t) buffer[pos+3]) | (((uint32_t)buffer[pos+2]) << 8) | (((uint32_t)buffer[pos+1]) << 16) | (((uint32_t) buffer[pos])) << 24)
+
+// HCI CMD OGF/OCF
+#define READ_CMD_OGF(buffer) (buffer[1] >> 2)
+#define READ_CMD_OCF(buffer) ((buffer[1] & 0x03) << 8 | buffer[0])
+
+// check if command complete event for given command
+#define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode)
+#define COMMAND_STATUS_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_STATUS && READ_BT_16(event,4) == cmd.opcode)
+
+// Code+Len=2, Pkts+Opcode=3; total=5
+#define OFFSET_OF_DATA_IN_COMMAND_COMPLETE 5
+
+// ACL Packet
+#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff)
+#define READ_ACL_FLAGS( buffer )      ( buffer[1] >> 4 )
+#define READ_ACL_LENGTH( buffer )     (READ_BT_16(buffer, 2))
+
+// L2CAP Packet
+#define READ_L2CAP_LENGTH(buffer)     ( READ_BT_16(buffer, 4))
+#define READ_L2CAP_CHANNEL_ID(buffer) ( READ_BT_16(buffer, 6))
+
+void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+void bt_flip_addr(bd_addr_t dest, bd_addr_t src);
+
+void net_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+
+void hexdump(void *data, int size);
+void printUUID(uint8_t *uuid);
+
+// @deprecated please use more convenient bd_addr_to_str
+void print_bd_addr( bd_addr_t addr);
+char * bd_addr_to_str(bd_addr_t addr);
+
+int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
+    
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum);
+uint8_t crc8_calc(uint8_t *data, uint16_t len);
+
+#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
+#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
+
+#if defined __cplusplus
+}
+#endif
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack_memory.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  btstsack_memory.h
+ *
+ *  @brief BTstack memory management via configurable memory pools
+ *
+ *  @note code semi-atuomatically generated by btstack_memory_generator.py
+ *
+ */
+
+#include "btstack_memory.h"
+#include <btstack/memory_pool.h>
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "hci.h"
+#include "l2cap.h"
+#include "rfcomm.h"
+
+// MARK: hci_connection_t
+#ifdef MAX_NO_HCI_CONNECTIONS
+#if MAX_NO_HCI_CONNECTIONS > 0
+static hci_connection_t hci_connection_storage[MAX_NO_HCI_CONNECTIONS];
+static memory_pool_t hci_connection_pool;
+void * btstack_memory_hci_connection_get(void){
+    return memory_pool_get(&hci_connection_pool);
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+    memory_pool_free(&hci_connection_pool, hci_connection);
+}
+#else
+void * btstack_memory_hci_connection_get(void){
+    return NULL;
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_hci_connection_get(void){
+    return malloc(sizeof(hci_connection_t));
+}
+void  btstack_memory_hci_connection_free(void *hci_connection){
+    free(hci_connection);
+}
+#endif
+
+
+// MARK: l2cap_service_t
+#ifdef MAX_NO_L2CAP_SERVICES
+#if MAX_NO_L2CAP_SERVICES > 0
+static l2cap_service_t l2cap_service_storage[MAX_NO_L2CAP_SERVICES];
+static memory_pool_t l2cap_service_pool;
+void * btstack_memory_l2cap_service_get(void){
+    return memory_pool_get(&l2cap_service_pool);
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+    memory_pool_free(&l2cap_service_pool, l2cap_service);
+}
+#else
+void * btstack_memory_l2cap_service_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_service_get(void){
+    return malloc(sizeof(l2cap_service_t));
+}
+void  btstack_memory_l2cap_service_free(void *l2cap_service){
+    free(l2cap_service);
+}
+#endif
+
+
+// MARK: l2cap_channel_t
+#ifdef MAX_NO_L2CAP_CHANNELS
+#if MAX_NO_L2CAP_CHANNELS > 0
+static l2cap_channel_t l2cap_channel_storage[MAX_NO_L2CAP_CHANNELS];
+static memory_pool_t l2cap_channel_pool;
+void * btstack_memory_l2cap_channel_get(void){
+    return memory_pool_get(&l2cap_channel_pool);
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    memory_pool_free(&l2cap_channel_pool, l2cap_channel);
+}
+#else
+void * btstack_memory_l2cap_channel_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_channel_get(void){
+    return malloc(sizeof(l2cap_channel_t));
+}
+void  btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    free(l2cap_channel);
+}
+#endif
+
+
+// MARK: rfcomm_multiplexer_t
+#ifdef MAX_NO_RFCOMM_MULTIPLEXERS
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+static rfcomm_multiplexer_t rfcomm_multiplexer_storage[MAX_NO_RFCOMM_MULTIPLEXERS];
+static memory_pool_t rfcomm_multiplexer_pool;
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return memory_pool_get(&rfcomm_multiplexer_pool);
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    memory_pool_free(&rfcomm_multiplexer_pool, rfcomm_multiplexer);
+}
+#else
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return malloc(sizeof(rfcomm_multiplexer_t));
+}
+void  btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    free(rfcomm_multiplexer);
+}
+#endif
+
+
+// MARK: rfcomm_service_t
+#ifdef MAX_NO_RFCOMM_SERVICES
+#if MAX_NO_RFCOMM_SERVICES > 0
+static rfcomm_service_t rfcomm_service_storage[MAX_NO_RFCOMM_SERVICES];
+static memory_pool_t rfcomm_service_pool;
+void * btstack_memory_rfcomm_service_get(void){
+    return memory_pool_get(&rfcomm_service_pool);
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    memory_pool_free(&rfcomm_service_pool, rfcomm_service);
+}
+#else
+void * btstack_memory_rfcomm_service_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_service_get(void){
+    return malloc(sizeof(rfcomm_service_t));
+}
+void  btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    free(rfcomm_service);
+}
+#endif
+
+
+// MARK: rfcomm_channel_t
+#ifdef MAX_NO_RFCOMM_CHANNELS
+#if MAX_NO_RFCOMM_CHANNELS > 0
+static rfcomm_channel_t rfcomm_channel_storage[MAX_NO_RFCOMM_CHANNELS];
+static memory_pool_t rfcomm_channel_pool;
+void * btstack_memory_rfcomm_channel_get(void){
+    return memory_pool_get(&rfcomm_channel_pool);
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    memory_pool_free(&rfcomm_channel_pool, rfcomm_channel);
+}
+#else
+void * btstack_memory_rfcomm_channel_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_channel_get(void){
+    return malloc(sizeof(rfcomm_channel_t));
+}
+void  btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    free(rfcomm_channel);
+}
+#endif
+
+
+// MARK: db_mem_device_name_t
+#ifdef MAX_NO_DB_MEM_DEVICE_NAMES
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+static db_mem_device_name_t db_mem_device_name_storage[MAX_NO_DB_MEM_DEVICE_NAMES];
+static memory_pool_t db_mem_device_name_pool;
+void * btstack_memory_db_mem_device_name_get(void){
+    return memory_pool_get(&db_mem_device_name_pool);
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    memory_pool_free(&db_mem_device_name_pool, db_mem_device_name);
+}
+#else
+void * btstack_memory_db_mem_device_name_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_name_get(void){
+    return malloc(sizeof(db_mem_device_name_t));
+}
+void  btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    free(db_mem_device_name);
+}
+#endif
+
+
+// MARK: db_mem_device_link_key_t
+#ifdef MAX_NO_DB_MEM_DEVICE_LINK_KEYS
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+static db_mem_device_link_key_t db_mem_device_link_key_storage[MAX_NO_DB_MEM_DEVICE_LINK_KEYS];
+static memory_pool_t db_mem_device_link_key_pool;
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return memory_pool_get(&db_mem_device_link_key_pool);
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    memory_pool_free(&db_mem_device_link_key_pool, db_mem_device_link_key);
+}
+#else
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return malloc(sizeof(db_mem_device_link_key_t));
+}
+void  btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    free(db_mem_device_link_key);
+}
+#endif
+
+
+// MARK: db_mem_service_t
+#ifdef MAX_NO_DB_MEM_SERVICES
+#if MAX_NO_DB_MEM_SERVICES > 0
+static db_mem_service_t db_mem_service_storage[MAX_NO_DB_MEM_SERVICES];
+static memory_pool_t db_mem_service_pool;
+void * btstack_memory_db_mem_service_get(void){
+    return memory_pool_get(&db_mem_service_pool);
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+    memory_pool_free(&db_mem_service_pool, db_mem_service);
+}
+#else
+void * btstack_memory_db_mem_service_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_service_get(void){
+    return malloc(sizeof(db_mem_service_t));
+}
+void  btstack_memory_db_mem_service_free(void *db_mem_service){
+    free(db_mem_service);
+}
+#endif
+
+// init
+void btstack_memory_init(void){
+#if MAX_NO_HCI_CONNECTIONS > 0
+    memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NO_HCI_CONNECTIONS, sizeof(hci_connection_t));
+#endif
+#if MAX_NO_L2CAP_SERVICES > 0
+    memory_pool_create(&l2cap_service_pool, l2cap_service_storage, MAX_NO_L2CAP_SERVICES, sizeof(l2cap_service_t));
+#endif
+#if MAX_NO_L2CAP_CHANNELS > 0
+    memory_pool_create(&l2cap_channel_pool, l2cap_channel_storage, MAX_NO_L2CAP_CHANNELS, sizeof(l2cap_channel_t));
+#endif
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+    memory_pool_create(&rfcomm_multiplexer_pool, rfcomm_multiplexer_storage, MAX_NO_RFCOMM_MULTIPLEXERS, sizeof(rfcomm_multiplexer_t));
+#endif
+#if MAX_NO_RFCOMM_SERVICES > 0
+    memory_pool_create(&rfcomm_service_pool, rfcomm_service_storage, MAX_NO_RFCOMM_SERVICES, sizeof(rfcomm_service_t));
+#endif
+#if MAX_NO_RFCOMM_CHANNELS > 0
+    memory_pool_create(&rfcomm_channel_pool, rfcomm_channel_storage, MAX_NO_RFCOMM_CHANNELS, sizeof(rfcomm_channel_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+    memory_pool_create(&db_mem_device_name_pool, db_mem_device_name_storage, MAX_NO_DB_MEM_DEVICE_NAMES, sizeof(db_mem_device_name_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+    memory_pool_create(&db_mem_device_link_key_pool, db_mem_device_link_key_storage, MAX_NO_DB_MEM_DEVICE_LINK_KEYS, sizeof(db_mem_device_link_key_t));
+#endif
+#if MAX_NO_DB_MEM_SERVICES > 0
+    memory_pool_create(&db_mem_service_pool, db_mem_service_storage, MAX_NO_DB_MEM_SERVICES, sizeof(db_mem_service_t));
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/btstack_memory.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  btstsack_memory.h
+ *
+ *  @brief BTstack memory management via configurable memory pools
+ *
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+void btstack_memory_init(void);
+
+void * btstack_memory_hci_connection_get(void);
+void   btstack_memory_hci_connection_free(void *hci_connection);
+void * btstack_memory_l2cap_service_get(void);
+void   btstack_memory_l2cap_service_free(void *l2cap_service);
+void * btstack_memory_l2cap_channel_get(void);
+void   btstack_memory_l2cap_channel_free(void *l2cap_channel);
+void * btstack_memory_rfcomm_multiplexer_get(void);
+void   btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer);
+void * btstack_memory_rfcomm_service_get(void);
+void   btstack_memory_rfcomm_service_free(void *rfcomm_service);
+void * btstack_memory_rfcomm_channel_get(void);
+void   btstack_memory_rfcomm_channel_free(void *rfcomm_channel);
+void * btstack_memory_db_mem_device_name_get(void);
+void   btstack_memory_db_mem_device_name_free(void *db_mem_device_name);
+void * btstack_memory_db_mem_device_link_key_get(void);
+void   btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key);
+void * btstack_memory_db_mem_service_get(void);
+void   btstack_memory_db_mem_service_free(void *db_mem_service);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/config.h	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_cpu.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_cpu.h>
+
+void hal_cpu_disable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs_and_sleep(){
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hal_mbed/hal_tick.cpp	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_tick.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_tick.h>
+#include "mbed.h"
+static Ticker tick;
+
+static void dummy_handler(void){};
+
+static void (*tick_handler)(void) = &dummy_handler;
+
+void hal_tick_init(void){
+
+}
+
+void hal_tick_set_handler(void (*handler)(void)){
+    if (handler == NULL){
+        tick_handler = &dummy_handler;
+        return;
+    }
+    tick_handler = handler;
+    tick.attach(tick_handler, 0.001);
+}
+
+int  hal_tick_get_tick_period_in_ms(void){
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,1409 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci.c
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#include "config.h"
+
+#include "hci.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef EMBEDDED
+#include <unistd.h> // gethostbyname
+#include <btstack/version.h>
+#endif
+
+#include "btstack_memory.h"
+#include "debug.h"
+#include "hci_dump.h"
+
+#include <btstack/hci_cmds.h>
+
+#define HCI_CONNECTION_TIMEOUT_MS 10000
+
+#ifdef USE_BLUETOOL
+#include "bt_control_iphone.h"
+#endif
+
+static void hci_update_scan_enable(void);
+
+// the STACK is here
+static hci_stack_t       hci_stack;
+
+/**
+ * get connection for a given handle
+ *
+ * @return connection OR NULL, if not found
+ */
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ((hci_connection_t *) it)->con_handle == con_handle){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+static void hci_connection_timeout_handler(timer_source_t *timer){
+    hci_connection_t * connection = (hci_connection_t *) linked_item_get_user(&timer->item);
+#ifdef HAVE_TIME
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    if (tv.tv_sec >= connection->timestamp.tv_sec + HCI_CONNECTION_TIMEOUT_MS/1000) {
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+#ifdef HAVE_TICK
+    if (embedded_get_ticks() > connection->timestamp + embedded_ticks_for_ms(HCI_CONNECTION_TIMEOUT_MS)){
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+    run_loop_set_timer(timer, HCI_CONNECTION_TIMEOUT_MS);
+    run_loop_add_timer(timer);
+}
+
+static void hci_connection_timestamp(hci_connection_t *connection){
+#ifdef HAVE_TIME
+    gettimeofday(&connection->timestamp, NULL);
+#endif
+#ifdef HAVE_TICK
+    connection->timestamp = embedded_get_ticks();
+#endif
+}
+
+/**
+ * create connection for given address
+ *
+ * @return connection OR NULL, if no memory left
+ */
+static hci_connection_t * create_connection_for_addr(bd_addr_t addr){
+    hci_connection_t * conn = (hci_connection_t *) btstack_memory_hci_connection_get();
+    if (!conn) return NULL;
+    BD_ADDR_COPY(conn->address, addr);
+    conn->con_handle = 0xffff;
+    conn->authentication_flags = AUTH_FLAGS_NONE;
+    linked_item_set_user(&conn->timeout.item, conn);
+    conn->timeout.process = hci_connection_timeout_handler;
+    hci_connection_timestamp(conn);
+    conn->acl_recombination_length = 0;
+    conn->acl_recombination_pos = 0;
+    conn->num_acl_packets_sent = 0;
+    linked_list_add(&hci_stack.connections, (linked_item_t *) conn);
+    return conn;
+}
+
+/**
+ * get connection for given address
+ *
+ * @return connection OR NULL, if not found
+ */
+static hci_connection_t * connection_for_address(bd_addr_t address){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ! BD_ADDR_CMP( ((hci_connection_t *) it)->address, address) ){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+inline static void connectionSetAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags | flags);
+}
+
+inline static void connectionClearAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags & ~flags);
+}
+
+
+/**
+ * add authentication flags and reset timer
+ */
+static void hci_add_connection_flags_for_flipped_bd_addr(uint8_t *bd_addr, hci_authentication_flags_t flags){
+    bd_addr_t addr;
+    bt_flip_addr(addr, *(bd_addr_t *) bd_addr);
+    hci_connection_t * conn = connection_for_address(addr);
+    if (conn) {
+        connectionSetAuthenticationFlags(conn, flags);
+        hci_connection_timestamp(conn);
+    }
+}
+
+int  hci_authentication_active_for_handle(hci_con_handle_t handle){
+    hci_connection_t * conn = connection_for_handle(handle);
+    if (!conn) return 0;
+    if (!conn->authentication_flags) return 0;
+    if (conn->authentication_flags & SENT_LINK_KEY_REPLY) return 0;
+    if (conn->authentication_flags & RECV_LINK_KEY_NOTIFICATION) return 0;
+    return 1;
+}
+
+void hci_drop_link_key_for_bd_addr(bd_addr_t *addr){
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->delete_link_key(addr);
+    }
+}
+
+
+/**
+ * count connections
+ */
+static int nr_hci_connections(void){
+    int count = 0;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next, count++);
+    return count;
+}
+
+/** 
+ * Dummy handler called by HCI
+ */
+static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+}
+
+uint8_t hci_number_outgoing_packets(hci_con_handle_t handle){
+    hci_connection_t * connection = connection_for_handle(handle);
+    if (!connection) {
+        log_error("hci_number_outgoing_packets connectino for handle %u does not exist!\n", handle);
+        return 0;
+    }
+    return connection->num_acl_packets_sent;
+}
+
+uint8_t hci_number_free_acl_slots(){
+    uint8_t free_slots = hci_stack.total_num_acl_packets;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        hci_connection_t * connection = (hci_connection_t *) it;
+        if (free_slots < connection->num_acl_packets_sent) {
+            log_error("hci_number_free_acl_slots: sum of outgoing packets > total acl packets!\n");
+            return 0;
+        }
+        free_slots -= connection->num_acl_packets_sent;
+    }
+    return free_slots;
+}
+
+int hci_can_send_packet_now(uint8_t packet_type){
+
+    // check for async hci transport implementations
+    if (hci_stack.hci_transport->can_send_packet_now){
+        if (!hci_stack.hci_transport->can_send_packet_now(packet_type)){
+            return 0;
+        }
+    }
+    
+    // check regular Bluetooth flow control
+    switch (packet_type) {
+        case HCI_ACL_DATA_PACKET:
+            return hci_number_free_acl_slots();
+        case HCI_COMMAND_DATA_PACKET:
+            return hci_stack.num_cmd_packets;
+        default:
+            return 0;
+    }
+}
+
+int hci_send_acl_packet(uint8_t *packet, int size){
+
+    // check for free places on BT module
+    if (!hci_number_free_acl_slots()) return BTSTACK_ACL_BUFFERS_FULL;
+    
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *connection = connection_for_handle( con_handle);
+    if (!connection) return 0;
+    hci_connection_timestamp(connection);
+    
+    // count packet
+    connection->num_acl_packets_sent++;
+    // log_info("hci_send_acl_packet - handle %u, sent %u\n", connection->con_handle, connection->num_acl_packets_sent);
+
+    // send packet 
+    int err = hci_stack.hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
+    
+    return err;
+}
+
+static void acl_handler(uint8_t *packet, int size){
+
+    // get info
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *conn      = connection_for_handle(con_handle);
+    uint8_t  acl_flags          = READ_ACL_FLAGS(packet);
+    uint16_t acl_length         = READ_ACL_LENGTH(packet);
+
+    // ignore non-registered handle
+    if (!conn){
+        log_error( "hci.c: acl_handler called with non-registered handle %u!\n" , con_handle);
+        return;
+    }
+    
+    // update idle timestamp
+    hci_connection_timestamp(conn);
+    
+    // handle different packet types
+    switch (acl_flags & 0x03) {
+            
+        case 0x01: // continuation fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos == 0) {
+                log_error( "ACL Cont Fragment but no first fragment for handle 0x%02x\n", con_handle);
+                return;
+            }
+            
+            // append fragment payload (header already stored)
+            memcpy(&conn->acl_recombination_buffer[conn->acl_recombination_pos], &packet[4], acl_length );
+            conn->acl_recombination_pos += acl_length;
+            
+            // log_error( "ACL Cont Fragment: acl_len %u, combined_len %u, l2cap_len %u\n", acl_length,
+            //        conn->acl_recombination_pos, conn->acl_recombination_length);  
+            
+            // forward complete L2CAP packet if complete. 
+            if (conn->acl_recombination_pos >= conn->acl_recombination_length + 4 + 4){ // pos already incl. ACL header
+                
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, conn->acl_recombination_buffer, conn->acl_recombination_pos);
+                // reset recombination buffer
+                conn->acl_recombination_length = 0;
+                conn->acl_recombination_pos = 0;
+            }
+            break;
+            
+        case 0x02: { // first fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos) {
+                log_error( "ACL First Fragment but data in buffer for handle 0x%02x\n", con_handle);
+                return;
+            }
+
+            // peek into L2CAP packet!
+            uint16_t l2cap_length = READ_L2CAP_LENGTH( packet );
+
+            // log_error( "ACL First Fragment: acl_len %u, l2cap_len %u\n", acl_length, l2cap_length);
+
+            // compare fragment size to L2CAP packet size
+            if (acl_length >= l2cap_length + 4){
+                
+                // forward fragment as L2CAP packet
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, packet, acl_length + 4);
+            
+            } else {
+                // store first fragment and tweak acl length for complete package
+                memcpy(conn->acl_recombination_buffer, packet, acl_length + 4);
+                conn->acl_recombination_pos    = acl_length + 4;
+                conn->acl_recombination_length = l2cap_length;
+                bt_store_16(conn->acl_recombination_buffer, 2, l2cap_length +4);
+            }
+            break;
+            
+        } 
+        default:
+            log_error( "hci.c: acl_handler called with invalid packet boundary flags %u\n", acl_flags & 0x03);
+            return;
+    }
+    
+    // execute main loop
+    hci_run();
+}
+
+static void hci_shutdown_connection(hci_connection_t *conn){
+    log_info("Connection closed: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+
+    // cancel all l2cap connections
+    hci_emit_disconnection_complete(conn->con_handle, 0x16);    // terminated by local host
+
+    run_loop_remove_timer(&conn->timeout);
+    
+    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+    btstack_memory_hci_connection_free( conn );
+    
+    // now it's gone
+    hci_emit_nr_connections_changed();
+}
+
+static const uint16_t packet_type_sizes[] = {
+    0, HCI_ACL_2DH1_SIZE, HCI_ACL_3DH1_SIZE, HCI_ACL_DM1_SIZE,
+    HCI_ACL_DH1_SIZE, 0, 0, 0,
+    HCI_ACL_2DH3_SIZE, HCI_ACL_3DH3_SIZE, HCI_ACL_DM3_SIZE, HCI_ACL_DH3_SIZE,
+    HCI_ACL_2DH5_SIZE, HCI_ACL_3DH5_SIZE, HCI_ACL_DM5_SIZE, HCI_ACL_DH5_SIZE
+};
+
+static uint16_t hci_acl_packet_types_for_buffer_size(uint16_t buffer_size){
+    uint16_t packet_types = 0;
+    int i;
+    for (i=0;i<16;i++){
+        if (packet_type_sizes[i] == 0) continue;
+        if (packet_type_sizes[i] <= buffer_size){
+            packet_types |= 1 << i;
+        }
+    }
+    // flip bits for "may not be used"
+    packet_types ^= 0x3306;
+    return packet_types;
+}
+
+uint16_t hci_usable_acl_packet_types(void){
+    return hci_stack.packet_types;
+}
+
+uint8_t* hci_get_outgoing_acl_packet_buffer(void){
+    // hci packet buffer is >= acl data packet length
+    return hci_stack.hci_packet_buffer;
+}
+
+uint16_t hci_max_acl_data_packet_length(){
+    return hci_stack.acl_data_packet_length;
+}
+
+// avoid huge local variables
+#ifndef EMBEDDED
+static device_name_t device_name;
+#endif
+static void event_handler(uint8_t *packet, int size){
+    bd_addr_t addr;
+    uint8_t link_type;
+    hci_con_handle_t handle;
+    hci_connection_t * conn;
+    int i;
+        
+    // printf("HCI:EVENT:%02x\n", packet[0]);
+    
+    switch (packet[0]) {
+                        
+        case HCI_EVENT_COMMAND_COMPLETE:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u\n", hci_stack.num_cmd_packets, packet[2]);
+            hci_stack.num_cmd_packets = packet[2];
+            
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_buffer_size)){
+                // from offset 5
+                // status 
+                // "The HC_ACL_Data_Packet_Length return parameter will be used to determine the size of the L2CAP segments contained in ACL Data Packets"
+                hci_stack.acl_data_packet_length = READ_BT_16(packet, 6);
+                // ignore: SCO data packet len (8)
+                hci_stack.total_num_acl_packets  = packet[9];
+                // ignore: total num SCO packets
+                if (hci_stack.state == HCI_STATE_INITIALIZING){
+                    // determine usable ACL payload size
+                    if (HCI_ACL_PAYLOAD_SIZE < hci_stack.acl_data_packet_length){
+                        hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+                    }
+                    // determine usable ACL packet types
+                    hci_stack.packet_types = hci_acl_packet_types_for_buffer_size(hci_stack.acl_data_packet_length);
+                    
+                    log_error("hci_read_buffer_size: used size %u, count %u, packet types %04x\n",
+                             hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets, hci_stack.packet_types); 
+                }
+            }
+            // Dump local address
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)) {
+                bd_addr_t addr;
+                bt_flip_addr(addr, &packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1]);
+                log_info("Local Address, Status: 0x%02x: Addr: %s\n",
+                    packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE], bd_addr_to_str(addr));
+            }
+            if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+                hci_emit_discoverable_enabled(hci_stack.discoverable);
+            }
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u\n", hci_stack.num_cmd_packets, packet[3]);
+            hci_stack.num_cmd_packets = packet[3];
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            for (i=0; i<packet[2];i++){
+                handle = READ_BT_16(packet, 3 + 2*i);
+                uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
+                conn = connection_for_handle(handle);
+                if (!conn){
+                    log_error("hci_number_completed_packet lists unused con handle %u\n", handle);
+                    continue;
+                }
+                conn->num_acl_packets_sent -= num_packets;
+                // log_info("hci_number_completed_packet %u processed for handle %u, outstanding %u\n", num_packets, handle, conn->num_acl_packets_sent);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_REQUEST:
+            bt_flip_addr(addr, &packet[2]);
+            // TODO: eval COD 8-10
+            link_type = packet[11];
+            log_info("Connection_incoming: %s, type %u\n", bd_addr_to_str(addr), link_type);
+            if (link_type == 1) { // ACL
+                conn = connection_for_address(addr);
+                if (!conn) {
+                    conn = create_connection_for_addr(addr);
+                }
+                if (!conn) {
+                    // CONNECTION REJECTED DUE TO LIMITED RESOURCES (0X0D)
+                    hci_stack.decline_reason = 0x0d;
+                    BD_ADDR_COPY(hci_stack.decline_addr, addr);
+                    break;
+                }
+                conn->state = RECEIVED_CONNECTION_REQUEST;
+                hci_run();
+            } else {
+                // SYNCHRONOUS CONNECTION LIMIT TO A DEVICE EXCEEDED (0X0A)
+                hci_stack.decline_reason = 0x0a;
+                BD_ADDR_COPY(hci_stack.decline_addr, addr);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            // Connection management
+            bt_flip_addr(addr, &packet[5]);
+            log_info("Connection_complete (status=%u) %s\n", packet[2], bd_addr_to_str(addr));
+            conn = connection_for_address(addr);
+            if (conn) {
+                if (!packet[2]){
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 3);
+                    
+                    // restart timer
+                    run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                } else {
+                    // connection failed, remove entry
+                    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                    btstack_memory_hci_connection_free( conn );
+                    
+                    // if authentication error, also delete link key
+                    if (packet[2] == 0x05) {
+                        hci_drop_link_key_for_bd_addr(&addr);
+                    }
+                }
+            }
+            break;
+
+        case HCI_EVENT_LINK_KEY_REQUEST:
+            log_info("HCI_EVENT_LINK_KEY_REQUEST\n");
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_REQUEST);
+            if (!hci_stack.remote_device_db) break;
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], HANDLE_LINK_KEY_REQUEST);
+            hci_run();
+            // request handled by hci_run() as HANDLE_LINK_KEY_REQUEST gets set
+            return;
+            
+        case HCI_EVENT_LINK_KEY_NOTIFICATION:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_NOTIFICATION);
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->put_link_key(&addr, (link_key_t *) &packet[8]);
+            // still forward event to allow dismiss of pairing dialog
+            break;
+            
+        case HCI_EVENT_PIN_CODE_REQUEST:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_PIN_CODE_REQUEST);
+            // PIN CODE REQUEST means the link key request didn't succee -> delete stored link key
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+            break;
+            
+#ifndef EMBEDDED
+        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
+            if (!hci_stack.remote_device_db) break;
+            if (packet[2]) break; // status not ok
+            bt_flip_addr(addr, &packet[3]);
+            // fix for invalid remote names - terminate on 0xff
+            for (i=0; i<248;i++){
+                if (packet[9+i] == 0xff){
+                    packet[9+i] = 0;
+                    break;
+                }
+            }
+            memset(&device_name, 0, sizeof(device_name_t));
+            strncpy((char*) device_name, (char*) &packet[9], 248);
+            hci_stack.remote_device_db->put_name(&addr, &device_name);
+            break;
+            
+        case HCI_EVENT_INQUIRY_RESULT:
+        case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
+            if (!hci_stack.remote_device_db) break;
+            // first send inq result packet
+            hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+            // then send cached remote names
+            for (i=0; i<packet[2];i++){
+                bt_flip_addr(addr, &packet[3+i*6]);
+                if (hci_stack.remote_device_db->get_name(&addr, &device_name)){
+                    hci_emit_remote_name_cached(&addr, &device_name);
+                }
+            }
+            return;
+#endif
+            
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            if (!packet[2]){
+                handle = READ_BT_16(packet, 3);
+                hci_connection_t * conn = connection_for_handle(handle);
+                if (conn) {
+                    hci_shutdown_connection(conn);
+                }
+            }
+            break;
+            
+        case HCI_EVENT_HARDWARE_ERROR:
+            if(hci_stack.control->hw_error){
+                (*hci_stack.control->hw_error)();
+            }
+            break;
+
+#ifdef HAVE_BLE
+        case HCI_EVENT_LE_META:
+            switch (packet[2]) {
+                case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+                    // Connection management
+                    bt_flip_addr(addr, &packet[8]);
+                    log_info("LE Connection_complete (status=%u) %s\n", packet[3], bd_addr_to_str(addr));
+                    // LE connections are auto-accepted, so just create a connection if there isn't one already
+                    conn = connection_for_address(addr);
+                    if (packet[3]){
+                        if (conn){
+                            // outgoing connection failed, remove entry
+                            linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                            btstack_memory_hci_connection_free( conn );
+                            
+                        }
+                        // if authentication error, also delete link key
+                        if (packet[3] == 0x05) {
+                            hci_drop_link_key_for_bd_addr(&addr);
+                        }
+                        break;
+                    }
+                    if (!conn){
+                        conn = create_connection_for_addr(addr);
+                    }
+                    if (!conn){
+                        // no memory
+                        break;
+                    }
+                    
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 4);
+                    
+                    // TODO: store - role, peer address type, conn_interval, conn_latency, supervision timeout, master clock
+
+                    // restart timer
+                    // run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    // run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+#endif            
+            
+        default:
+            break;
+    }
+
+    // handle BT initialization
+    if (hci_stack.state == HCI_STATE_INITIALIZING){
+        // handle H4 synchronization loss on restart
+        // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
+        //    hci_stack.substate = 0;
+        // }
+        // handle normal init sequence
+        if (hci_stack.substate % 2){
+            // odd: waiting for event
+            if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
+                hci_stack.substate++;
+            }
+        }
+    }
+    
+    // help with BT sleep
+    if (hci_stack.state == HCI_STATE_FALLING_ASLEEP
+        && hci_stack.substate == 1
+        && COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+        hci_stack.substate++;
+    }
+    
+    hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+    
+    // execute main loop
+    hci_run();
+}
+
+void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+/** Register HCI packet handlers */
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
+    hci_stack.packet_handler = handler;
+}
+
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db){
+    
+    // reference to use transport layer implementation
+    hci_stack.hci_transport = transport;
+    
+    // references to used control implementation
+    hci_stack.control = control;
+    
+    // reference to used config
+    hci_stack.config = config;
+    
+    // no connections yet
+    hci_stack.connections = NULL;
+    hci_stack.discoverable = 0;
+    hci_stack.connectable = 0;
+    
+    // no pending cmds
+    hci_stack.decline_reason = 0;
+    hci_stack.new_scan_enable_value = 0xff;
+    
+    // higher level handler
+    hci_stack.packet_handler = dummy_handler;
+
+    // store and open remote device db
+    hci_stack.remote_device_db = remote_device_db;
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->open();
+    }
+    
+    // max acl payload size defined in config.h
+    hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+    
+    // register packet handlers with transport
+    transport->register_packet_handler(&packet_handler);
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+void hci_close(){
+    // close remote device db
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->close();
+    }
+    while (hci_stack.connections) {
+        hci_shutdown_connection((hci_connection_t *) hci_stack.connections);
+}
+    hci_power_control(HCI_POWER_OFF);
+}
+
+// State-Module-Driver overview
+// state                    module  low-level 
+// HCI_STATE_OFF             off      close
+// HCI_STATE_INITIALIZING,   on       open
+// HCI_STATE_WORKING,        on       open
+// HCI_STATE_HALTING,        on       open
+// HCI_STATE_SLEEPING,    off/sleep   close
+// HCI_STATE_FALLING_ASLEEP  on       open
+
+static int hci_power_control_on(void){
+    
+    // power on
+    int err = 0;
+    if (hci_stack.control && hci_stack.control->on){
+        err = (*hci_stack.control->on)(hci_stack.config);
+    }
+    if (err){
+        log_error( "POWER_ON failed\n");
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    
+    // open low-level device
+    err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    return 0;
+}
+
+static void hci_power_control_off(void){
+    
+    log_info("hci_power_control_off\n");
+
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+
+    log_info("hci_power_control_off - hci_transport closed\n");
+    
+    // power off
+    if (hci_stack.control && hci_stack.control->off){
+        (*hci_stack.control->off)(hci_stack.config);
+    }
+    
+    log_info("hci_power_control_off - control closed\n");
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+static void hci_power_control_sleep(void){
+    
+    log_info("hci_power_control_sleep\n");
+    
+#if 0
+    // don't close serial port during sleep
+    
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+#endif
+    
+    // sleep mode
+    if (hci_stack.control && hci_stack.control->sleep){
+        (*hci_stack.control->sleep)(hci_stack.config);
+    }
+    
+    hci_stack.state = HCI_STATE_SLEEPING;
+}
+
+static int hci_power_control_wake(void){
+    
+    log_info("hci_power_control_wake\n");
+
+    // wake on
+    if (hci_stack.control && hci_stack.control->wake){
+        (*hci_stack.control->wake)(hci_stack.config);
+    }
+    
+#if 0
+    // open low-level device
+    int err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+#endif
+    
+    return 0;
+}
+
+
+int hci_power_control(HCI_POWER_MODE power_mode){
+    
+    log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state);
+    
+    int err = 0;
+    switch (hci_stack.state){
+            
+        case HCI_STATE_OFF:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    err = hci_power_control_on();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing (with SLEEP == OFF)
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_INITIALIZING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // no connections yet, just turn it off
+                    hci_power_control_off();
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // no connections yet, just turn it off
+                    hci_power_control_sleep();
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_WORKING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_HALTING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // set up state machine
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch (power_mode){
+                case HCI_POWER_ON:
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        break;
+                    }
+#endif
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_SLEEPING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        hci_update_scan_enable();
+                        break;
+                    }
+#endif
+                    err = hci_power_control_wake();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+    }
+
+    // create internal event
+    hci_emit_state();
+    
+    // trigger next/first action
+    hci_run();
+    
+    return 0;
+}
+
+static void hci_update_scan_enable(void){
+    // 2 = page scan, 1 = inq scan
+    hci_stack.new_scan_enable_value  = hci_stack.connectable << 1 | hci_stack.discoverable;
+    hci_run();
+}
+
+void hci_discoverable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    if (hci_stack.discoverable == enable){
+        hci_emit_discoverable_enabled(hci_stack.discoverable);
+        return;
+    }
+
+    hci_stack.discoverable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_connectable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    // don't emit event
+    if (hci_stack.connectable == enable) return;
+
+    hci_stack.connectable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_run(){
+        
+    hci_connection_t * connection;
+    linked_item_t * it;
+    
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // global/non-connection oriented commands
+    
+    // decline incoming connections
+    if (hci_stack.decline_reason){
+        uint8_t reason = hci_stack.decline_reason;
+        hci_stack.decline_reason = 0;
+        hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason);
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // send scan enable
+    if (hci_stack.new_scan_enable_value != 0xff){
+        hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value);
+        hci_stack.new_scan_enable_value = 0xff;
+    }
+    
+    // send pending HCI commands
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+        connection = (hci_connection_t *) it;
+        
+        if (connection->state == RECEIVED_CONNECTION_REQUEST){
+            log_info("sending hci_accept_connection_request\n");
+            hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
+            connection->state = ACCEPTED_CONNECTION_REQUEST;
+        }
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+        if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){
+            link_key_t link_key;
+            log_info("responding to link key request\n");
+            if (hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){
+               hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key);
+            } else {
+               hci_send_cmd(&hci_link_key_request_negative_reply, connection->address);
+            }
+            connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
+        }
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+    switch (hci_stack.state){
+        case HCI_STATE_INITIALIZING:
+            // log_info("hci_init: substate %u\n", hci_stack.substate);
+            if (hci_stack.substate % 2) {
+                // odd: waiting for command completion
+                return;
+            }
+            switch (hci_stack.substate >> 1){
+                case 0: // RESET
+                    hci_send_cmd(&hci_reset);
+                    if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){
+                        // skip baud change
+                        hci_stack.substate = 4; // >> 1 = 2
+                    }
+                    break;
+                case 1: // SEND BAUD CHANGE
+                    hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer);
+                    hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]);
+                    break;
+                case 2: // LOCAL BAUD CHANGE
+                    hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main);
+                    hci_stack.substate += 2;
+                    // break missing here for fall through
+                    
+                case 3:
+                    // custom initialization
+                    if (hci_stack.control && hci_stack.control->next_cmd){
+                        int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer);
+                        if (valid_cmd){
+                            int size = 3 + hci_stack.hci_packet_buffer[2];
+                            hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size);
+                            hci_stack.substate = 4; // more init commands
+                            break;
+                        }
+                        log_info("hci_run: init script done\n\r");
+                    }
+                    // otherwise continue
+                    hci_send_cmd(&hci_read_bd_addr);
+                    break;
+                case 4:
+                    hci_send_cmd(&hci_read_buffer_size);
+                    break;
+                case 5:
+                    // ca. 15 sec
+                    hci_send_cmd(&hci_write_page_timeout, 0x6000);
+                    break;
+                case 6:
+                    hci_send_cmd(&hci_write_scan_enable, (hci_stack.connectable << 1) | hci_stack.discoverable); // page scan
+                    break;
+                case 7:
+#ifndef EMBEDDED
+                {
+                    char hostname[30];
+                    gethostname(hostname, 30);
+                    hostname[29] = '\0';
+                    hci_send_cmd(&hci_write_local_name, hostname);
+                    break;
+                }
+                case 8:
+#ifdef USE_BLUETOOL
+                    hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone
+                    break;
+                    
+                case 9:
+#endif
+#endif
+                    // done.
+                    hci_stack.state = HCI_STATE_WORKING;
+                    hci_emit_state();
+                    break;
+                default:
+                    break;
+            }
+            hci_stack.substate++;
+            break;
+            
+        case HCI_STATE_HALTING:
+
+            log_info("HCI_STATE_HALTING\n");
+            // close all open connections
+            connection =  (hci_connection_t *) hci_stack.connections;
+            if (connection){
+                
+                // send disconnect
+                if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                
+                log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+
+                // send disconnected event right away - causes higher layer connections to get closed, too.
+                hci_shutdown_connection(connection);
+                return;
+            }
+            log_info("HCI_STATE_HALTING, calling off\n");
+            
+            // switch mode
+            hci_power_control_off();
+            
+            log_info("HCI_STATE_HALTING, emitting state\n");
+            hci_emit_state();
+            log_info("HCI_STATE_HALTING, done\n");
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch(hci_stack.substate) {
+                case 0:
+                    log_info("HCI_STATE_FALLING_ASLEEP\n");
+                    // close all open connections
+                    connection =  (hci_connection_t *) hci_stack.connections;
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't close connections, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        connection = NULL;
+                    }
+#endif
+                    if (connection){
+                        
+                        // send disconnect
+                        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+                        log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                        hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+                        
+                        // send disconnected event right away - causes higher layer connections to get closed, too.
+                        hci_shutdown_connection(connection);
+                        return;
+                    }
+                    
+                    // disable page and inquiry scan
+                    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                    
+                    log_info("HCI_STATE_HALTING, disabling inq cans\n");
+                    hci_send_cmd(&hci_write_scan_enable, hci_stack.connectable << 1); // drop inquiry scan but keep page scan
+                    
+                    // continue in next sub state
+                    hci_stack.substate++;
+                    break;
+                case 1:
+                    // wait for command complete "hci_write_scan_enable" in event_handler();
+                    break;
+                case 2:
+                    log_info("HCI_STATE_HALTING, calling sleep\n");
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't actually go to sleep, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        // SLEEP MODE reached
+                        hci_stack.state = HCI_STATE_SLEEPING; 
+                        hci_emit_state();
+                        break;
+                    }
+#endif
+                    // switch mode
+                    hci_power_control_sleep();  // changes hci_stack.state to SLEEP
+                    hci_emit_state();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+int hci_send_cmd_packet(uint8_t *packet, int size){
+    bd_addr_t addr;
+    hci_connection_t * conn;
+    // house-keeping
+    
+    // create_connection?
+    if (IS_COMMAND(packet, hci_create_connection)){
+        bt_flip_addr(addr, &packet[3]);
+        log_info("Create_connection to %s\n", bd_addr_to_str(addr));
+        conn = connection_for_address(addr);
+        if (conn) {
+            // if connection exists
+            if (conn->state == OPEN) {
+                // and OPEN, emit connection complete command
+                hci_emit_connection_complete(conn, 0);
+            }
+            //    otherwise, just ignore as it is already in the open process
+            return 0; // don't sent packet to controller
+            
+        }
+        // create connection struct and register, state = SENT_CREATE_CONNECTION
+        conn = create_connection_for_addr(addr);
+        if (!conn){
+            // notify client that alloc failed
+            hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
+            return 0; // don't sent packet to controller
+        }
+        conn->state = SENT_CREATE_CONNECTION;
+    }
+    
+    if (IS_COMMAND(packet, hci_link_key_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_link_key_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_NEGATIVE_REQUEST);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_NEGATIVE_REPLY);
+    }
+    
+    if (IS_COMMAND(packet, hci_delete_stored_link_key)){
+        if (hci_stack.remote_device_db){
+            bt_flip_addr(addr, &packet[3]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+        }
+    }
+    
+    hci_stack.num_cmd_packets--;
+    return hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
+}
+
+/**
+ * pre: numcmds >= 0 - it's allowed to send a command to the controller
+ */
+int hci_send_cmd(const hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t size = hci_create_cmd_internal(hci_stack.hci_packet_buffer, cmd, argptr);
+    va_end(argptr);
+    return hci_send_cmd_packet(hci_stack.hci_packet_buffer, size);
+}
+
+// Create various non-HCI events. 
+// TODO: generalize, use table similar to hci_create_command
+
+void hci_emit_state(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_STATE;
+    event[1] = sizeof(event) - 2;
+    event[2] = hci_stack.state;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
+    uint8_t event[13];
+    event[0] = HCI_EVENT_CONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, conn->con_handle);
+    bt_flip_addr(&event[5], conn->address);
+    event[11] = 1; // ACL connection
+    event[12] = 0; // encryption disabled
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
+    uint8_t event[6];
+    event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0; // status = OK
+    bt_store_16(event, 3, handle);
+    event[5] = reason;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn){
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_TIMEOUT_CHECK;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, conn->con_handle);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_nr_connections_changed(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_NR_CONNECTIONS_CHANGED;
+    event[1] = sizeof(event) - 2;
+    event[2] = nr_hci_connections();
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_hci_open_failed(){
+    uint8_t event[2];
+    event[0] = BTSTACK_EVENT_POWERON_FAILED;
+    event[1] = sizeof(event) - 2;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+#ifndef EMBEDDED
+void hci_emit_btstack_version() {
+    uint8_t event[6];
+    event[0] = BTSTACK_EVENT_VERSION;
+    event[1] = sizeof(event) - 2;
+    event[2] = BTSTACK_MAJOR;
+    event[3] = BTSTACK_MINOR;
+    bt_store_16(event, 4, BTSTACK_REVISION);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+#endif
+
+void hci_emit_system_bluetooth_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name){
+    uint8_t event[2+1+6+248];
+    event[0] = BTSTACK_EVENT_REMOTE_NAME_CACHED;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0;   // just to be compatible with HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
+    bt_flip_addr(&event[3], *addr);
+    memcpy(&event[9], name, 248);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_discoverable_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_DISCOVERABLE_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci.h
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <btstack/hci_cmds.h>
+#include <btstack/utils.h>
+#include "hci_transport.h"
+#include "bt_control.h"
+#include "remote_device_db.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+// packet header sizes
+#define HCI_CMD_HEADER_SIZE          3
+#define HCI_ACL_HEADER_SIZE   	     4
+#define HCI_SCO_HEADER_SIZE  	     3
+#define HCI_EVENT_HEADER_SIZE        2
+
+// packet sizes (max payload)
+#define HCI_ACL_DM1_SIZE            17
+#define HCI_ACL_DH1_SIZE            27
+#define HCI_ACL_2DH1_SIZE           54
+#define HCI_ACL_3DH1_SIZE           83
+#define HCI_ACL_DM3_SIZE           121
+#define HCI_ACL_DH3_SIZE           183
+#define HCI_ACL_DM5_SIZE           224
+#define HCI_ACL_DH5_SIZE           339
+#define HCI_ACL_2DH3_SIZE          367
+#define HCI_ACL_3DH3_SIZE          552
+#define HCI_ACL_2DH5_SIZE          679
+#define HCI_ACL_3DH5_SIZE         1021
+       
+#define HCI_EVENT_PAYLOAD_SIZE     255
+#define HCI_CMD_PAYLOAD_SIZE       255
+    
+// packet buffer sizes
+// HCI_ACL_PAYLOAD_SIZE is configurable and defined in config.h
+#define HCI_EVENT_BUFFER_SIZE      (HCI_EVENT_HEADER_SIZE + HCI_EVENT_PAYLOAD_SIZE)
+#define HCI_CMD_BUFFER_SIZE        (HCI_CMD_HEADER_SIZE   + HCI_CMD_PAYLOAD_SIZE)
+#define HCI_ACL_BUFFER_SIZE        (HCI_ACL_HEADER_SIZE   + HCI_ACL_PAYLOAD_SIZE)
+    
+// size of hci buffers, big enough for command, event, or acl packet without H4 packet type
+// @note cmd buffer is bigger than event buffer
+#if HCI_ACL_BUFFER_SIZE > HCI_CMD_BUFFER_SIZE
+#define HCI_PACKET_BUFFER_SIZE HCI_ACL_BUFFER_SIZE
+#else
+#define HCI_PACKET_BUFFER_SIZE HCI_CMD_BUFFER_SIZE
+#endif
+    
+// OGFs
+#define OGF_LINK_CONTROL          0x01
+#define OGF_LINK_POLICY           0x02
+#define OGF_CONTROLLER_BASEBAND   0x03
+#define OGF_INFORMATIONAL_PARAMETERS 0x04
+#define OGF_LE_CONTROLLER 0x08
+#define OGF_BTSTACK 0x3d
+#define OGF_VENDOR  0x3f
+
+// cmds for BTstack 
+// get state: @returns HCI_STATE
+#define BTSTACK_GET_STATE                                  0x01
+
+// set power mode: @param HCI_POWER_MODE
+#define BTSTACK_SET_POWER_MODE                             0x02
+
+// set capture mode: @param on
+#define BTSTACK_SET_ACL_CAPTURE_MODE                       0x03
+
+// get BTstack version
+#define BTSTACK_GET_VERSION                                0x04
+
+// get system Bluetooth state
+#define BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED               0x05
+
+// set system Bluetooth state
+#define BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED               0x06
+
+// enable inquiry scan for this client
+#define BTSTACK_SET_DISCOVERABLE                           0x07
+
+// set global Bluetooth state
+#define BTSTACK_SET_BLUETOOTH_ENABLED                      0x08
+
+// create l2cap channel: @param bd_addr(48), psm (16)
+#define L2CAP_CREATE_CHANNEL                               0x20
+
+// disconnect l2cap disconnect, @param channel(16), reason(8)
+#define L2CAP_DISCONNECT                                   0x21
+
+// register l2cap service: @param psm(16), mtu (16)
+#define L2CAP_REGISTER_SERVICE                             0x22
+
+// unregister l2cap disconnect, @param psm(16)
+#define L2CAP_UNREGISTER_SERVICE                           0x23
+
+// accept connection @param bd_addr(48), dest cid (16)
+#define L2CAP_ACCEPT_CONNECTION                            0x24
+
+// decline l2cap disconnect,@param bd_addr(48), dest cid (16), reason(8)
+#define L2CAP_DECLINE_CONNECTION                           0x25
+
+// create l2cap channel: @param bd_addr(48), psm (16), mtu (16)
+#define L2CAP_CREATE_CHANNEL_MTU                           0x26
+
+// register SDP Service Record: service record (size)
+#define SDP_REGISTER_SERVICE_RECORD                        0x30
+
+// unregister SDP Service Record
+#define SDP_UNREGISTER_SERVICE_RECORD                      0x31
+
+// RFCOMM "HCI" Commands
+#define RFCOMM_CREATE_CHANNEL       0x40
+#define RFCOMM_DISCONNECT			0x41
+#define RFCOMM_REGISTER_SERVICE     0x42
+#define RFCOMM_UNREGISTER_SERVICE   0x43
+#define RFCOMM_ACCEPT_CONNECTION    0x44
+#define RFCOMM_DECLINE_CONNECTION   0x45
+#define RFCOMM_PERSISTENT_CHANNEL   0x46
+#define RFCOMM_CREATE_CHANNEL_WITH_CREDITS   0x47
+#define RFCOMM_REGISTER_SERVICE_WITH_CREDITS 0x48
+#define RFCOMM_GRANT_CREDITS                 0x49
+    
+// 
+#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_OPENED                     0x50
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_CLOSED                     0x51
+
+// data: event(8), nr_connections(8)
+#define DAEMON_NR_CONNECTIONS_CHANGED                      0x52
+
+// data: event(8)
+#define DAEMON_EVENT_NEW_RFCOMM_CREDITS                    0x53
+
+// data: event()
+#define DAEMON_EVENT_HCI_PACKET_SENT                       0x54
+    
+/**
+ * Connection State 
+ */
+typedef enum {
+    AUTH_FLAGS_NONE                = 0x00,
+    RECV_LINK_KEY_REQUEST          = 0x01,
+    HANDLE_LINK_KEY_REQUEST        = 0x02,
+    SENT_LINK_KEY_REPLY            = 0x04,
+    SENT_LINK_KEY_NEGATIVE_REQUEST = 0x08,
+    RECV_LINK_KEY_NOTIFICATION     = 0x10,
+    RECV_PIN_CODE_REQUEST          = 0x20,
+    SENT_PIN_CODE_REPLY            = 0x40, 
+    SENT_PIN_CODE_NEGATIVE_REPLY   = 0x80 
+} hci_authentication_flags_t;
+
+typedef enum {
+    SENT_CREATE_CONNECTION = 1,
+    RECEIVED_CONNECTION_REQUEST,
+    ACCEPTED_CONNECTION_REQUEST,
+    REJECTED_CONNECTION_REQUEST,
+    OPEN,
+    SENT_DISCONNECT
+} CONNECTION_STATE;
+
+typedef enum {
+    BLUETOOTH_OFF = 1,
+    BLUETOOTH_ON,
+    BLUETOOTH_ACTIVE
+} BLUETOOTH_STATE;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // remote side
+    bd_addr_t address;
+    
+    // module handle
+    hci_con_handle_t con_handle;
+
+    // state
+    CONNECTION_STATE state;
+    
+    // errands
+    hci_authentication_flags_t authentication_flags;
+
+    timer_source_t timeout;
+    
+#ifdef HAVE_TIME
+    // timer
+    struct timeval timestamp;
+#endif
+#ifdef HAVE_TICK
+    uint32_t timestamp; // timeout in system ticks
+#endif
+    
+    // ACL packet recombination - ACL Header + ACL payload
+    uint8_t  acl_recombination_buffer[4 + HCI_ACL_BUFFER_SIZE];
+    uint16_t acl_recombination_pos;
+    uint16_t acl_recombination_length;
+    
+    // number ACL packets sent to controller
+    uint8_t num_acl_packets_sent;
+    
+} hci_connection_t;
+
+/**
+ * main data structure
+ */
+typedef struct {
+    // transport component with configuration
+    hci_transport_t  * hci_transport;
+    void             * config;
+    
+    // hardware power controller
+    bt_control_t     * control;
+    
+    // list of existing baseband connections
+    linked_list_t     connections;
+
+    // single buffer for HCI Command assembly
+    uint8_t          hci_packet_buffer[HCI_PACKET_BUFFER_SIZE]; // opcode (16), len(8)
+    
+    /* host to controller flow control */
+    uint8_t  num_cmd_packets;
+    // uint8_t  total_num_cmd_packets;
+    uint8_t  total_num_acl_packets;
+    uint16_t acl_data_packet_length;
+
+    // usable packet types given acl_data_packet_length and HCI_ACL_BUFFER_SIZE
+    uint16_t packet_types;
+    
+    /* callback to L2CAP layer */
+    void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+    /* remote device db */
+    remote_device_db_t const*remote_device_db;
+    
+    /* hci state machine */
+    HCI_STATE state;
+    uint8_t   substate;
+    uint8_t   cmds_ready;
+    
+    uint8_t   discoverable;
+    uint8_t   connectable;
+    
+    /* buffer for scan enable cmd - 0xff no change */
+    uint8_t   new_scan_enable_value;
+    
+    // buffer for single connection decline
+    uint8_t   decline_reason;
+    bd_addr_t decline_addr;
+    
+} hci_stack_t;
+
+// create and send hci command packets based on a template and a list of parameters
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...);
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr);
+
+// set up HCI
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db);
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+void hci_close(void);
+
+// power and inquriy scan control
+int  hci_power_control(HCI_POWER_MODE mode);
+void hci_discoverable_control(uint8_t enable);
+void hci_connectable_control(uint8_t enable);
+
+/**
+ * run the hci control loop once
+ */
+void hci_run(void);
+
+// create and send hci command packets based on a template and a list of parameters
+int hci_send_cmd(const hci_cmd_t *cmd, ...);
+
+// send complete CMD packet
+int hci_send_cmd_packet(uint8_t *packet, int size);
+
+// send ACL packet
+int hci_send_acl_packet(uint8_t *packet, int size);
+
+// non-blocking UART driver needs
+int hci_can_send_packet_now(uint8_t packet_type);
+    
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle);
+uint8_t  hci_number_outgoing_packets(hci_con_handle_t handle);
+uint8_t  hci_number_free_acl_slots(void);
+int      hci_authentication_active_for_handle(hci_con_handle_t handle);
+void     hci_drop_link_key_for_bd_addr(bd_addr_t *addr);
+uint16_t hci_max_acl_data_packet_length(void);
+uint16_t hci_usable_acl_packet_types(void);
+uint8_t* hci_get_outgoing_acl_packet_buffer(void);
+
+// 
+void hci_emit_state(void);
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status);
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn);
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason);
+void hci_emit_nr_connections_changed(void);
+void hci_emit_hci_open_failed(void);
+void hci_emit_btstack_version(void);
+void hci_emit_system_bluetooth_enabled(uint8_t enabled);
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name);
+void hci_emit_discoverable_enabled(uint8_t enabled);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_cmds.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_cmds.c
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include <btstack/hci_cmds.h>
+
+#include <string.h>
+
+#include <btstack/sdp_util.h>
+#include "config.h"
+#include "hci.h"
+
+// calculate combined ogf/ocf value
+#define OPCODE(ogf, ocf) (ocf | ogf << 10)
+
+/**
+ * construct HCI Command based on template
+ *
+ * Format:
+ *   1,2,3,4: one to four byte value
+ *   H: HCI connection handle
+ *   B: Bluetooth Baseband Address (BD_ADDR)
+ *   E: Extended Inquiry Result
+ *   N: Name up to 248 chars, \0 terminated
+ *   P: 16 byte Pairing code
+ *   S: Service Record (Data Element Sequence)
+ */
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr){
+    
+    hci_cmd_buffer[0] = cmd->opcode & 0xff;
+    hci_cmd_buffer[1] = cmd->opcode >> 8;
+    int pos = 3;
+    
+    const char *format = cmd->format;
+    uint16_t word;
+    uint32_t longword;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+            case 'H': // hci_handle
+                word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                hci_cmd_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } else if (*format == 'H') {
+                    // TODO implement opaque client connection handles
+                    //      pass module handle for now
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } 
+                break;
+            case '3':
+            case '4':
+                longword = va_arg(argptr, uint32_t);
+                // longword = va_arg(argptr, int);
+                hci_cmd_buffer[pos++] = longword;
+                hci_cmd_buffer[pos++] = longword >> 8;
+                hci_cmd_buffer[pos++] = longword >> 16;
+                if (*format == '4'){
+                    hci_cmd_buffer[pos++] = longword >> 24;
+                }
+                break;
+            case 'B': // bt-addr
+                ptr = va_arg(argptr, uint8_t *);
+                hci_cmd_buffer[pos++] = ptr[5];
+                hci_cmd_buffer[pos++] = ptr[4];
+                hci_cmd_buffer[pos++] = ptr[3];
+                hci_cmd_buffer[pos++] = ptr[2];
+                hci_cmd_buffer[pos++] = ptr[1];
+                hci_cmd_buffer[pos++] = ptr[0];
+                break;
+            case 'E': // Extended Inquiry Information 240 octets
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 240);
+                pos += 240;
+                break;
+            case 'N': { // UTF-8 string, null terminated
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = strlen((const char*) ptr);
+                if (len > 248) {
+                    len = 248;
+                }
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                if (len < 248) {
+                    // fill remaining space with zeroes
+                    memset(&hci_cmd_buffer[pos+len], 0, 248-len);
+                }
+                pos += 248;
+                break;
+            }
+            case 'P': // 16 byte PIN code or link key
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 16);
+                pos += 16;
+                break;
+#ifdef HAVE_BLE
+            case 'A': // 31 bytes advertising data
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 31);
+                pos += 31;
+                break;
+#endif
+#ifdef HAVE_SDP
+            case 'S': { // Service Record (Data Element Sequence)
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = de_get_len(ptr);
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                pos += len;
+                break;
+            }
+#endif
+            default:
+                break;
+        }
+        format++;
+    };
+    hci_cmd_buffer[2] = pos - 3;
+    return pos;
+}
+
+/**
+ * construct HCI Command based on template
+ *
+ * mainly calls hci_create_cmd_internal
+ */
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t len = hci_create_cmd_internal(hci_cmd_buffer, cmd, argptr);
+    va_end(argptr);
+    return len;
+}
+
+
+/**
+ *  Link Control Commands 
+ */
+const hci_cmd_t hci_inquiry = {
+OPCODE(OGF_LINK_CONTROL, 0x01), "311"
+// LAP, Inquiry length, Num_responses
+};
+const hci_cmd_t hci_inquiry_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x02), ""
+// no params
+};
+const hci_cmd_t hci_create_connection = {
+OPCODE(OGF_LINK_CONTROL, 0x05), "B21121"
+// BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+};
+const hci_cmd_t hci_disconnect = {
+OPCODE(OGF_LINK_CONTROL, 0x06), "H1"
+// Handle, Reason: 0x05, 0x13-0x15, 0x1a, 0x29
+// see Errors Codes in BT Spec Part D
+};
+const hci_cmd_t hci_create_connection_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x08), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_accept_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x09), "B1"
+// BD_ADDR, Role: become master, stay slave
+};
+const hci_cmd_t hci_reject_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x0a), "B1"
+// BD_ADDR, reason e.g. CONNECTION REJECTED DUE TO LIMITED RESOURCES (0x0d)
+};
+const hci_cmd_t hci_link_key_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0b), "BP"
+// BD_ADDR, LINK_KEY
+};
+const hci_cmd_t hci_link_key_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0c), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_pin_code_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0d), "B1P"
+// BD_ADDR, pin length, PIN: c-string
+};
+const hci_cmd_t hci_pin_code_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0e), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_authentication_requested = {
+OPCODE(OGF_LINK_CONTROL, 0x11), "H"
+// Handle
+};
+const hci_cmd_t hci_set_connection_encryption = {
+OPCODE(OGF_LINK_CONTROL, 0x13), "H1"
+// Handle, Encryption_Enable
+};
+const hci_cmd_t hci_change_connection_link_key = {
+OPCODE(OGF_LINK_CONTROL, 0x15), "H"
+// Handle
+};
+const hci_cmd_t hci_remote_name_request = {
+OPCODE(OGF_LINK_CONTROL, 0x19), "B112"
+// BD_ADDR, Page_Scan_Repetition_Mode, Reserved, Clock_Offset
+};
+const hci_cmd_t hci_remote_name_request_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x1A), "B"
+// BD_ADDR
+};
+
+/**
+ *  Link Policy Commands 
+ */
+const hci_cmd_t hci_sniff_mode = {
+OPCODE(OGF_LINK_POLICY, 0x03), "H2222"
+// handle, Sniff_Max_Interval, Sniff_Min_Interval, Sniff_Attempt, Sniff_Timeout:
+};
+const hci_cmd_t hci_qos_setup = {
+OPCODE(OGF_LINK_POLICY, 0x07), "H114444"
+// handle, flags, service_type, token rate (bytes/s), peak bandwith (bytes/s),
+// latency (us), delay_variation (us)
+};
+const hci_cmd_t hci_role_discovery = {
+OPCODE(OGF_LINK_POLICY, 0x09), "H"
+// handle
+};
+const hci_cmd_t hci_switch_role_command= {
+OPCODE(OGF_LINK_POLICY, 0x0b), "B1"
+// BD_ADDR, role: {0=master,1=slave}
+};
+const hci_cmd_t hci_read_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0c), "H"
+// handle 
+};
+const hci_cmd_t hci_write_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0d), "H2"
+// handle, settings
+};
+
+/**
+ *  Controller & Baseband Commands 
+ */
+const hci_cmd_t hci_set_event_mask = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x01), "44"
+// event_mask lower 4 octets, higher 4 bytes
+};
+const hci_cmd_t hci_reset = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_delete_stored_link_key = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x12), "B1"
+// BD_ADDR, Delete_All_Flag
+};
+const hci_cmd_t hci_write_local_name = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x13), "N"
+// Local name (UTF-8, Null Terminated, max 248 octets)
+};
+const hci_cmd_t hci_write_page_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x18), "2"
+// Page_Timeout * 0.625 ms
+};
+const hci_cmd_t hci_write_scan_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x1A), "1"
+// Scan_enable: no, inq, page, inq+page
+};
+const hci_cmd_t hci_write_authentication_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x20), "1"
+// Authentication_Enable
+};
+const hci_cmd_t hci_write_class_of_device = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x24), "3"
+// Class of Device
+};
+const hci_cmd_t hci_read_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x29), ""
+};
+const hci_cmd_t hci_write_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x2a), "1"
+// Num broadcast retransmissions (e.g. 0 for a single broadcast)
+};
+const hci_cmd_t hci_host_buffer_size = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122"
+// Host_ACL_Data_Packet_Length:, Host_Synchronous_Data_Packet_Length:, Host_Total_Num_ACL_Data_Packets:, Host_Total_Num_Synchronous_Data_Packets:
+};
+const hci_cmd_t hci_read_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x36), "H"
+// handle
+};
+const hci_cmd_t hci_write_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x37), "H2"
+// handle, Range for N: 0x0001 Ð 0xFFFF Time (Range: 0.625ms Ð 40.9 sec)
+};
+const hci_cmd_t hci_write_inquiry_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x45), "1"
+// Inquiry mode: 0x00 = standard, 0x01 = with RSSI, 0x02 = extended
+};
+const hci_cmd_t hci_write_extended_inquiry_response = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x52), "1E"
+// FEC_Required, Exstended Inquiry Response
+};
+const hci_cmd_t hci_write_simple_pairing_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x56), "1"
+// mode: 0 = off, 1 = on
+};
+const hci_cmd_t hci_read_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6c), ""
+// params: none
+// return: status, le supported host, simultaneous le host
+};
+const hci_cmd_t hci_write_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6d), "11"
+// param: le supported host, simultaneous le host
+// return: status
+};
+
+/**
+ * Informational Parameters
+ */
+const hci_cmd_t hci_read_local_supported_features = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_read_buffer_size = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x05), ""
+// no params
+};
+const hci_cmd_t hci_read_bd_addr = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x09), ""
+// no params
+};
+
+#ifdef HAVE_BLE
+/**
+ * Low Energy Commands
+ */
+const hci_cmd_t hci_le_set_event_mask = {
+OPCODE(OGF_LE_CONTROLLER, 0x01), "44"
+// params: event_mask lower 4 octets, higher 4 bytes
+// return: status
+};
+const hci_cmd_t hci_le_read_buffer_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x02), ""
+// params: none
+// return: status, le acl data packet len (16), total num le acl data packets(8)
+};
+const hci_cmd_t hci_le_read_supported_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x03), ""
+// params: none
+// return: LE_Features See [Vol 6] Part B, Section 4.6
+};
+const hci_cmd_t hci_le_set_random_address = {
+OPCODE(OGF_LE_CONTROLLER, 0x05), "B"
+// params: random device address
+// return: status
+};
+const hci_cmd_t hci_le_set_advertising_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x06), "22111B11"
+// param: min advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: max advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: advertising type (enum from 0): ADV_IND, ADC_DIRECT_IND, ADV_SCAN_IND, ADV_NONCONN_IND
+// param: own address type (enum from 0): public device address, random device address
+// param: direct address type (enum from 0): public device address, random device address
+// param: direct address - public or random address of device to be connecteed
+// param: advertising channel map (flags): chan_37(1), chan_38(2), chan_39(4)
+// param: advertising filter policy (enum from 0): scan any conn any, scan whitelist, con any, scan any conn whitelist, scan whitelist, con whitelist
+// return: status
+};
+const hci_cmd_t hci_le_read_advertising_channel_tx_power = {
+OPCODE(OGF_LE_CONTROLLER, 0x07), ""
+// params: none
+// return: status, level [-20,10] signed int (8), units dBm
+};
+const hci_cmd_t hci_le_set_advertising_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x08), "1A"
+// param: advertising data len
+// param: advertising data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_response_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x09), "1A"
+// param: scan response data len
+// param: scan response data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_advertise_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0a), "1"
+// params: avertise enable: off (0), on (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x0b), "12211"
+// param: le scan type: passive (0), active (1)
+// param: le scan interval [0x0004,0x4000], unit: 0.625 msec
+// param: le scan window   [0x0004,0x4000], unit: 0.625 msec
+// param: own address type: public (0), random (1)
+// param: scanning filter policy: any (0), only whitelist (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0c), "11"
+// param: le scan enable:  disabled (0), enabled (1)
+// param: filter duplices: disabled (0), enabled (1)
+// return: status
+};
+const hci_cmd_t hci_le_create_connection= {
+OPCODE(OGF_LE_CONTROLLER, 0x0d), "2211B1222222"
+// param: le scan interval, [0x0004, 0x4000], unit: 0.625 msec
+// param: le scan window, [0x0004, 0x4000], unit: 0.625 msec
+// param: initiator filter policy: peer address type + peer address (0), whitelist (1)
+// param: peer address type: public (0), random (1)
+// param: peer address
+// param: own address type: public (0), random (1)
+// param: conn interval min, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn latency, number of connection events [0x0000, 0x01f4]
+// param: supervision timeout, [0x000a, 0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000, 0xffff], unit: 0.625 msec
+// return: none -> le create connection complete event
+};
+const hci_cmd_t hci_le_create_connection_cancel = {
+OPCODE(OGF_LE_CONTROLLER, 0x0e), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_read_white_list_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x0f), ""
+// params: none
+// return: status, number of entries in controller whitelist
+};
+const hci_cmd_t hci_le_clear_white_list = {
+OPCODE(OGF_LE_CONTROLLER, 0x10), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_add_device_to_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x11), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_remove_device_from_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x12), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_connection_update = {
+OPCODE(OGF_LE_CONTROLLER, 0x13), "H222222"
+// param: conn handle
+// param: conn interval min, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn latency, [0x0000,0x03e8], number of connection events
+// param: supervision timeout, [0x000a,0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000,0xffff], unit: 0.625 msec
+// param: maximum CE length, [0x0000,0xffff], unit: 0.625 msec
+// return: none -> le connection update complete event
+};
+const hci_cmd_t hci_le_set_host_channel_classification = {
+OPCODE(OGF_LE_CONTROLLER, 0x14), "41"
+// param: channel map 37 bit, split into first 32 and higher 5 bits
+// return: status
+};
+const hci_cmd_t hci_le_read_channel_map = {
+OPCODE(OGF_LE_CONTROLLER, 0x15), "H"
+// params: connection handle
+// return: status, connection handle, channel map (5 bytes, 37 used)
+};
+const hci_cmd_t hci_le_read_remote_used_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x16), "H"
+// params: connection handle
+// return: none -> le read remote used features complete event
+};
+const hci_cmd_t hci_le_encrypt = {
+OPCODE(OGF_LE_CONTROLLER, 0x17), "PP"
+// param: key (128) for AES-128
+// param: plain text (128) 
+// return: status, encrypted data (128)
+};
+const hci_cmd_t hci_le_rand = {
+OPCODE(OGF_LE_CONTROLLER, 0x18), ""
+// params: none
+// return: status, random number (64)
+};
+const hci_cmd_t hci_le_start_encryption = {
+OPCODE(OGF_LE_CONTROLLER, 0x19), "H442P"
+// param: connection handle
+// param: 64 bit random number lower  32 bit
+// param: 64 bit random number higher 32 bit
+// param: encryption diversifier (16)
+// param: long term key (128)
+// return: none -> encryption changed or encryption key refresh complete event
+};
+const hci_cmd_t hci_le_long_term_key_request_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1a), "HP"
+// param: connection handle
+// param: long term key (128)
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_long_term_key_negative_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1b), "H"
+// param: connection handle
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_read_supported_states = {
+OPCODE(OGF_LE_CONTROLLER, 0x1c), "H"
+// param: none
+// return: status, LE states (64)
+};
+const hci_cmd_t hci_le_receiver_test = {
+OPCODE(OGF_LE_CONTROLLER, 0x1d), "1"
+// param: rx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+// return: status
+};
+const hci_cmd_t hci_le_transmitter_test = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1e), "111"
+    // param: tx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+    // param: lengh of test payload [0x00,0x25]
+    // param: packet payload [0,7] different patterns
+    // return: status
+};
+const hci_cmd_t hci_le_test_end = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1f), "1"
+    // params: none
+    // return: status, number of packets (8)
+};
+#endif
+
+// BTstack commands
+const hci_cmd_t btstack_get_state = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_STATE), ""
+// no params -> 
+};
+
+const hci_cmd_t btstack_set_power_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_POWER_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_set_acl_capture_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_ACL_CAPTURE_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_get_version = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_VERSION), ""
+};
+
+const hci_cmd_t btstack_get_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED), ""
+};
+
+const hci_cmd_t btstack_set_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t btstack_set_discoverable = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_DISCOVERABLE), "1"
+};
+
+const hci_cmd_t btstack_set_bluetooth_enabled = {
+// only used by btstack config
+OPCODE(OGF_BTSTACK, BTSTACK_SET_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t l2cap_create_channel = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL), "B2"
+// @param bd_addr(48), psm (16)
+};
+const hci_cmd_t l2cap_create_channel_mtu = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL_MTU), "B22"
+// @param bd_addr(48), psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_disconnect = {
+OPCODE(OGF_BTSTACK, L2CAP_DISCONNECT), "21"
+// @param channel(16), reason(8)
+};
+const hci_cmd_t l2cap_register_service = {
+OPCODE(OGF_BTSTACK, L2CAP_REGISTER_SERVICE), "22"
+// @param psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_unregister_service = {
+OPCODE(OGF_BTSTACK, L2CAP_UNREGISTER_SERVICE), "2"
+// @param psm (16)
+};
+const hci_cmd_t l2cap_accept_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_ACCEPT_CONNECTION), "2"
+// @param source cid (16)
+};
+const hci_cmd_t l2cap_decline_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_DECLINE_CONNECTION), "21"
+// @param source cid (16), reason(8)
+};
+const hci_cmd_t sdp_register_service_record = {
+OPCODE(OGF_BTSTACK, SDP_REGISTER_SERVICE_RECORD), "S"
+// @param service record handle (DES)
+};
+const hci_cmd_t sdp_unregister_service_record = {
+OPCODE(OGF_BTSTACK, SDP_UNREGISTER_SERVICE_RECORD), "4"
+// @param service record handle (32)
+};
+
+// create rfcomm channel: @param bd_addr(48), channel (8)
+const hci_cmd_t rfcomm_create_channel = {
+	OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL), "B1"
+};
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+const hci_cmd_t rfcomm_create_channel_with_initial_credits = {
+	OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL_WITH_CREDITS), "B121"
+};
+// grant credits: @param rfcomm_cid(16), credits (8)
+const hci_cmd_t rfcomm_grants_credits= {
+	OPCODE(OGF_BTSTACK, RFCOMM_GRANT_CREDITS), "21"
+};
+// disconnect rfcomm disconnect, @param rfcomm_cid(16), reason(8)
+const  hci_cmd_t rfcomm_disconnect = {
+	OPCODE(OGF_BTSTACK, RFCOMM_DISCONNECT), "21"
+};
+
+// register rfcomm service: @param channel(8), mtu (16)
+const hci_cmd_t rfcomm_register_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "12"
+};
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+const hci_cmd_t rfcomm_register_service_with_initial_credits = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE_WITH_CREDITS), "121"
+};
+
+// unregister rfcomm service, @param service_channel(16)
+const hci_cmd_t rfcomm_unregister_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_UNREGISTER_SERVICE), "2"
+};
+// accept connection @param source cid (16)
+const hci_cmd_t rfcomm_accept_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_ACCEPT_CONNECTION), "2"
+};
+// decline connection @param source cid (16)
+const hci_cmd_t rfcomm_decline_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_DECLINE_CONNECTION), "21"
+};
+// request persisten rfcomm channel number for named service
+const hci_cmd_t rfcomm_persistent_channel_for_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_PERSISTENT_CHANNEL), "N"
+};
+
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_dump.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_dump.c
+ *
+ *  Dump HCI trace in various formats:
+ *
+ *  - BlueZ's hcidump format
+ *  - Apple's PacketLogger
+ *  - stdout hexdump
+ *
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#include "config.h"
+
+#include "hci_dump.h"
+#include "hci.h"
+#include "hci_transport.h"
+#include <btstack/hci_cmds.h>
+
+#ifndef EMBEDDED
+#include <fcntl.h>        // open
+#include <arpa/inet.h>    // hton..
+#include <unistd.h>       // write 
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>     // for timestamps
+#include <sys/stat.h>     // for mode flags
+#include <stdarg.h>       // for va_list
+#endif
+
+// BLUEZ hcidump
+typedef struct {
+	uint16_t	len;
+	uint8_t		in;
+	uint8_t		pad;
+	uint32_t	ts_sec;
+	uint32_t	ts_usec;
+    uint8_t     packet_type;
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif 
+hcidump_hdr;
+
+// APPLE PacketLogger
+typedef struct {
+	uint32_t	len;
+	uint32_t	ts_sec;
+	uint32_t	ts_usec;
+	uint8_t		type;   // 0xfc for note
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif
+pktlog_hdr;
+
+#ifndef EMBEDDED
+static int dump_file = -1;
+static int dump_format;
+static hcidump_hdr header_bluez;
+static pktlog_hdr  header_packetlogger;
+static char time_string[40];
+static int  max_nr_packets = -1;
+static int  nr_packets = 0;
+static char log_message_buffer[256];
+#endif
+
+void hci_dump_open(char *filename, hci_dump_format_t format){
+#ifndef EMBEDDED
+    dump_format = format;
+    if (dump_format == HCI_DUMP_STDOUT) {
+        dump_file = fileno(stdout);
+    } else {
+        dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    }
+#endif
+}
+
+#ifndef EMBEDDED
+void hci_dump_set_max_packets(int packets){
+    max_nr_packets = packets;
+}
+#endif
+
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
+#ifndef EMBEDDED
+
+    if (dump_file < 0) return; // not activated yet
+
+    // don't grow bigger than max_nr_packets
+    if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
+        if (nr_packets >= max_nr_packets){
+            lseek(dump_file, 0, SEEK_SET);
+            ftruncate(dump_file, 0);
+            nr_packets = 0;
+        }
+        nr_packets++;
+    }
+    
+    // get time
+    struct timeval curr_time;
+    struct tm* ptm;
+    gettimeofday(&curr_time, NULL);
+    
+    switch (dump_format){
+        case HCI_DUMP_STDOUT: {
+            /* Obtain the time of day, and convert it to a tm struct. */
+            ptm = localtime (&curr_time.tv_sec);
+            /* Format the date and time, down to a single second. */
+            strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
+            /* Compute milliseconds from microseconds. */
+            uint16_t milliseconds = curr_time.tv_usec / 1000;
+            /* Print the formatted time, in seconds, followed by a decimal point
+             and the milliseconds. */
+            printf ("%s.%03u] ", time_string, milliseconds);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    printf("CMD => ");
+                    break;
+                case HCI_EVENT_PACKET:
+                    printf("EVT <= ");
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        printf("ACL <= ");
+                    } else {
+                        printf("ACL => ");
+                    }
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    // assume buffer is big enough
+                    packet[len] = 0;
+                    printf("LOG -- %s\n", (char*) packet);
+                    return;
+                default:
+                    return;
+            }
+            hexdump(packet, len);
+            break;
+        }
+            
+        case HCI_DUMP_BLUEZ:
+            bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
+            header_bluez.in  = in;
+            header_bluez.pad = 0;
+            bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
+            bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
+            header_bluez.packet_type = packet_type;
+            write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        case HCI_DUMP_PACKETLOGGER:
+            header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
+            header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
+            header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    header_packetlogger.type = 0x00;
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        header_packetlogger.type = 0x03;
+                    } else {
+                        header_packetlogger.type = 0x02;
+                    }
+                    break;
+                case HCI_EVENT_PACKET:
+                    header_packetlogger.type = 0x01;
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    header_packetlogger.type = 0xfc;
+                    break;
+                default:
+                    return;
+            }
+            write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        default:
+            break;
+    }
+#endif
+}
+
+void hci_dump_log(const char * format, ...){
+#ifndef EMBEDDED
+    va_list argptr;
+    va_start(argptr, format);
+    int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
+    hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
+    va_end(argptr);
+#endif    
+}
+
+void hci_dump_close(){
+#ifndef EMBEDDED
+    close(dump_file);
+    dump_file = -1;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_dump.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_dump.h
+ *
+ *  Dump HCI trace as BlueZ's hcidump format, Apple's PacketLogger, or stdout
+ * 
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    HCI_DUMP_BLUEZ = 0,
+    HCI_DUMP_PACKETLOGGER,
+    HCI_DUMP_STDOUT
+} hci_dump_format_t;
+
+void hci_dump_open(char *filename, hci_dump_format_t format);
+void hci_dump_set_max_packets(int packets); // -1 for unlimited
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
+void hci_dump_log(const char * format, ...);
+void hci_dump_close(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_transport.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_transport.h
+ *
+ *  HCI Transport API -- allows BT Daemon to use different transport protcols 
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <btstack/run_loop.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+/* HCI packet types */
+typedef struct {
+    int    (*open)(void *transport_config);
+    int    (*close)(void *transport_config);
+    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);
+    void   (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+    const char * (*get_transport_name)(void);
+    // custom extension for UART transport implementations
+    int    (*set_baudrate)(uint32_t baudrate);
+    // support async transport layers, e.g. IRQ driven without buffers
+    int    (*can_send_packet_now)(uint8_t packet_type);
+} hci_transport_t;
+
+typedef struct {
+    const char *device_name;
+    uint32_t   baudrate_init; // initial baud rate
+    uint32_t   baudrate_main; // = 0: same as initial baudrate
+    int   flowcontrol; // 
+} hci_uart_config_t;
+
+
+// inline various hci_transport_X.h files
+extern hci_transport_t * hci_transport_h4_instance(void);
+extern hci_transport_t * hci_transport_h4_dma_instance(void);
+extern hci_transport_t * hci_transport_h4_iphone_instance(void);
+extern hci_transport_t * hci_transport_h5_instance(void);
+extern hci_transport_t * hci_transport_usb_instance(void);
+
+// support for "enforece wake device" in h4 - used by iOS power management
+extern void hci_transport_h4_iphone_set_enforce_wake_device(char *path);
+    
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/hci_transport_usb.cpp	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,133 @@
+/*
+ * 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 "USBHostBTstack.h"
+
+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 USBHostBTstack* 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);
+    if (bt) {
+        return bt->open();
+    }
+    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->register_packet_handler(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 USBHostBTstack;
+    }
+    if (!hci_transport_usb) {
+        hci_transport_usb = (hci_transport_t*)malloc( sizeof(hci_transport_t));
+        hci_transport_usb->open                          = usb_open;
+        hci_transport_usb->close                         = usb_close;
+        hci_transport_usb->send_packet                   = usb_send_packet;
+        hci_transport_usb->register_packet_handler       = usb_register_packet_handler;
+        hci_transport_usb->get_transport_name            = usb_get_transport_name;
+        hci_transport_usb->set_baudrate                  = NULL;
+        hci_transport_usb->can_send_packet_now           = NULL;
+    }
+    return hci_transport_usb;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap.c
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#include "l2cap.h"
+#include "hci.h"
+#include "hci_dump.h"
+#include "debug.h"
+#include "btstack_memory.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <stdio.h>
+
+// nr of buffered acl packets in outgoing queue to get max performance 
+#define NR_BUFFERED_ACL_PACKETS 3
+
+// used to cache l2cap rejects, echo, and informational requests
+#define NR_PENDING_SIGNALING_RESPONSES 3
+
+// offsets for L2CAP SIGNALING COMMANDS
+#define L2CAP_SIGNALING_COMMAND_CODE_OFFSET   0
+#define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET  1
+#define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
+#define L2CAP_SIGNALING_COMMAND_DATA_OFFSET   4
+
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+// used to cache l2cap rejects, echo, and informational requests
+static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
+static int signaling_responses_pending;
+
+static linked_list_t l2cap_channels = NULL;
+static linked_list_t l2cap_services = NULL;
+static void (*packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler;
+static int new_credits_blocked = 0;
+
+static btstack_packet_handler_t attribute_protocol_packet_handler = NULL;
+static btstack_packet_handler_t security_protocol_packet_handler = NULL;
+
+// prototypes
+static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
+static l2cap_service_t * l2cap_get_service(uint16_t psm);
+static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
+static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
+static void l2cap_emit_connection_request(l2cap_channel_t *channel);
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
+
+
+void l2cap_init(){
+    new_credits_blocked = 0;
+    signaling_responses_pending = 0;
+    
+    l2cap_channels = NULL;
+    l2cap_services = NULL;
+
+    packet_handler = null_packet_handler;
+    
+    // 
+    // register callback with HCI
+    //
+    hci_register_packet_handler(&l2cap_packet_handler);
+    hci_connectable_control(0); // no services yet
+}
+
+
+/** Register L2CAP packet handlers */
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+}
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
+    packet_handler = handler;
+}
+
+//  notify client/protocol handler
+void l2cap_dispatch(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
+    if (channel->packet_handler) {
+        (* (channel->packet_handler))(type, channel->local_cid, data, size);
+    } else {
+        (*packet_handler)(channel->connection, type, channel->local_cid, data, size);
+    }
+}
+
+void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
+    uint8_t event[21];
+    event[0] = L2CAP_EVENT_CHANNEL_OPENED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_flip_addr(&event[3], channel->address);
+    bt_store_16(event,  9, channel->handle);
+    bt_store_16(event, 11, channel->psm);
+    bt_store_16(event, 13, channel->local_cid);
+    bt_store_16(event, 15, channel->remote_cid);
+    bt_store_16(event, 17, channel->local_mtu);
+    bt_store_16(event, 19, channel->remote_mtu); 
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_CHANNEL_CLOSED;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_connection_request(l2cap_channel_t *channel) {
+    uint8_t event[16];
+    event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
+    event[1] = sizeof(event) - 2;
+    bt_flip_addr(&event[2], channel->address);
+    bt_store_16(event,  8, channel->handle);
+    bt_store_16(event, 10, channel->psm);
+    bt_store_16(event, 12, channel->local_cid);
+    bt_store_16(event, 14, channel->remote_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, psm);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*packet_handler)(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
+}
+
+void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) {
+    // track credits
+    channel->packets_granted += credits;
+    // log_info("l2cap_emit_credits for cid %u, credits given: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits);
+    
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_CREDITS;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    event[4] = credits;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_block_new_credits(uint8_t blocked){
+    new_credits_blocked = blocked;
+}
+
+void l2cap_hand_out_credits(void){
+
+    if (new_credits_blocked) return;    // we're told not to. used by daemon
+    
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        if (!hci_number_free_acl_slots()) return;
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->state != L2CAP_STATE_OPEN) continue;
+        if (hci_number_outgoing_packets(channel->handle) < NR_BUFFERED_ACL_PACKETS && channel->packets_granted == 0) {
+            l2cap_emit_credits(channel, 1);
+        }
+    }
+}
+
+l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( channel->local_cid == local_cid) {
+            return channel;
+        }
+    }
+    return NULL;
+}
+
+int  l2cap_can_send_packet_now(uint16_t local_cid){
+    l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) return 0;
+    if (!channel->packets_granted) return 0;
+    return hci_can_send_packet_now(HCI_ACL_DATA_PACKET);
+}
+
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        return channel->remote_mtu;
+    } 
+    return 0;
+}
+
+int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_signaling_packet, cannot send\n");
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    // log_info("l2cap_send_signaling_packet type %u\n", cmd);
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    va_list argptr;
+    va_start(argptr, identifier);
+    uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr);
+    va_end(argptr);
+    // log_info("l2cap_send_signaling_packet con %u!\n", handle);
+    return hci_send_acl_packet(acl_buffer, len);
+}
+
+uint8_t *l2cap_get_outgoing_buffer(void){
+    return hci_get_outgoing_acl_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
+}
+
+int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_send_internal no channel for cid %u\n", local_cid);
+        return -1;   // TODO: define error
+    }
+
+    if (channel->packets_granted == 0){
+        log_error("l2cap_send_internal cid %u, no credits!\n", local_cid);
+        return -1;  // TODO: define error
+    }
+    
+    --channel->packets_granted;
+
+    log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n",
+                  local_cid, channel->handle, channel->packets_granted);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, channel->remote_cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+    
+    return err;
+}
+
+int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_prepared_to_handle cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    log_debug("l2cap_send_prepared_to_handle cid %u, handle %u\n", cid, handle);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+
+    return err;
+}
+
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    memcpy(&acl_buffer[8], data, len);
+
+    return l2cap_send_prepared(local_cid, len);
+}
+
+int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    memcpy(&acl_buffer[8], data, len);
+    
+    return l2cap_send_prepared_connectionless(handle, cid, len);
+}
+
+static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
+}
+
+static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
+}
+
+
+
+// MARK: L2CAP_RUN
+// process outstanding signaling tasks
+void l2cap_run(void){
+    
+    // check pending signaling responses
+    while (signaling_responses_pending){
+        
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        hci_con_handle_t handle = signaling_responses[0].handle;
+        uint8_t sig_id = signaling_responses[0].sig_id;
+        uint16_t infoType = signaling_responses[0].data;    // INFORMATION_REQUEST
+        uint16_t result   = signaling_responses[0].data;    // CONNECTION_REQUEST
+        
+        switch (signaling_responses[0].code){
+            case CONNECTION_REQUEST:
+                l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0);
+                break;
+            case ECHO_REQUEST:
+                l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
+                break;
+            case INFORMATION_REQUEST:
+                if (infoType == 2) {
+                    uint32_t features = 0;
+                    // extended features request supported, however no features present
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features);
+                } else {
+                    // all other types are not supported
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
+                }
+                break;
+            default:
+                // should not happen
+                break;
+        }
+        
+        // remove first item
+        signaling_responses_pending--;
+        int i;
+        for (i=0; i < signaling_responses_pending; i++){
+            memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
+        }
+    }
+    
+    uint8_t  config_options[4];
+    linked_item_t *it;
+    linked_item_t *next;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = next){
+        next = it->next;    // cache next item as current item might get freed
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        
+        // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var);
+        
+        
+        switch (channel->state){
+
+            case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
+                // send connection request - set state first
+                channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
+                // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+                hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0);
+                // discard channel - l2cap_finialize_channel_close without sending l2cap close event
+                linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list
+                btstack_memory_l2cap_channel_free(channel); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
+                channel->state = L2CAP_STATE_CONFIG;
+                channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
+                // success, start l2cap handshake
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
+                l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);                   
+                break;
+            
+            case L2CAP_STATE_CONFIG:
+                if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
+                }
+                else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
+                    channel->local_sig_id = l2cap_next_sig_id();
+                    config_options[0] = 1; // MTU
+                    config_options[1] = 2; // len param
+                    bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options);
+                }
+                if (l2cap_channel_ready_for_open(channel)){
+                    channel->state = L2CAP_STATE_OPEN;
+                    l2cap_emit_channel_opened(channel, 0);  // success
+                    l2cap_emit_credits(channel, 1);
+                }
+                break;
+
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);   
+                l2cap_finialize_channel_close(channel);  // -- remove from list
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_DISCONNECT;
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);   
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+uint16_t l2cap_max_mtu(void){
+    return hci_max_acl_data_packet_length() - L2CAP_HEADER_SIZE;
+}
+
+// open outgoing L2CAP channel
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler,
+                                   bd_addr_t address, uint16_t psm, uint16_t mtu){
+    
+    // alloc structure
+    l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!chan) {
+        // emit error event
+        l2cap_channel_t dummy_channel;
+        BD_ADDR_COPY(dummy_channel.address, address);
+        dummy_channel.psm = psm;
+        l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED);
+        return;
+    }
+    // limit local mtu to max acl packet length
+    if (mtu > l2cap_max_mtu()) {
+        mtu = l2cap_max_mtu();
+    }
+        
+    // fill in 
+    BD_ADDR_COPY(chan->address, address);
+    chan->psm = psm;
+    chan->handle = 0;
+    chan->connection = connection;
+    chan->packet_handler = packet_handler;
+    chan->remote_mtu = L2CAP_MINIMAL_MTU;
+    chan->local_mtu = mtu;
+    chan->packets_granted = 0;
+    
+    // set initial state
+    chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
+    chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    chan->remote_sig_id = L2CAP_SIG_ID_INVALID;
+    chan->local_sig_id = L2CAP_SIG_ID_INVALID;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) chan);
+    
+    l2cap_run();
+}
+
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){
+    // find channel for local_cid
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+    }
+    // process
+    l2cap_run();
+}
+
+static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
+    linked_item_t *it = (linked_item_t *) &l2cap_channels;
+    while (it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // failure, forward error code
+                l2cap_emit_channel_opened(channel, status);
+                // discard channel
+                it->next = it->next->next;
+                btstack_memory_l2cap_channel_free(channel);
+            }
+        } else {
+            it = it->next;
+        }
+    }
+}
+
+static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // success, start l2cap handshake
+                channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
+                channel->handle = handle;
+                channel->local_cid = l2cap_next_local_cid();
+            }
+        }
+    }
+    // process
+    l2cap_run();
+}
+
+void l2cap_event_handler( uint8_t *packet, uint16_t size ){
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    l2cap_channel_t * channel;
+    linked_item_t *it;
+    int hci_con_used;
+    
+    switch(packet[0]){
+            
+        // handle connection complete events
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            bt_flip_addr(address, &packet[5]);
+            if (packet[2] == 0){
+                handle = READ_BT_16(packet, 3);
+                l2cap_handle_connection_success_for_addr(address, handle);
+            } else {
+                l2cap_handle_connection_failed_for_addr(address, packet[2]);
+            }
+            break;
+            
+        // handle successful create connection cancel command
+        case HCI_EVENT_COMMAND_COMPLETE:
+            if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) {
+                if (packet[5] == 0){
+                    bt_flip_addr(address, &packet[6]);
+                    // CONNECTION TERMINATED BY LOCAL HOST (0X16)
+                    l2cap_handle_connection_failed_for_addr(address, 0x16);
+                }
+            }
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        // handle disconnection complete events
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            // send l2cap disconnect events for all channels on this handle
+            handle = READ_BT_16(packet, 3);
+            it = (linked_item_t *) &l2cap_channels;
+            while (it->next){
+                l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+                if ( channel->handle == handle ){
+                    // update prev item before free'ing next element - don't call l2cap_finalize_channel_close
+                    it->next = it->next->next;
+                    l2cap_emit_channel_closed(channel);
+                    btstack_memory_l2cap_channel_free(channel);
+                } else {
+                    it = it->next;
+                }
+            }
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            l2cap_run();    // try sending signaling packets first
+            l2cap_hand_out_credits();
+            break;
+            
+        // HCI Connection Timeouts
+        case L2CAP_EVENT_TIMEOUT_CHECK:
+            handle = READ_BT_16(packet, 2);
+            if (hci_authentication_active_for_handle(handle)) break;
+            hci_con_used = 0;
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->handle == handle) {
+                    hci_con_used = 1;
+                }
+            }
+            if (hci_con_used) break;
+            if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+            hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection             
+            break;
+
+        case DAEMON_EVENT_HCI_PACKET_SENT:
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->packet_handler) {
+                    (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size);
+                } 
+            }
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            break;
+            
+        default:
+            break;
+    }
+    
+    // pass on
+    (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size);
+}
+
+static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
+    channel->remote_sig_id = identifier;
+    channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
+    l2cap_run();
+}
+
+static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){
+    // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused."
+    if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
+        signaling_responses[signaling_responses_pending].handle = handle;
+        signaling_responses[signaling_responses_pending].code = code;
+        signaling_responses[signaling_responses_pending].sig_id = sig_id;
+        signaling_responses[signaling_responses_pending].data = data;
+        signaling_responses_pending++;
+        l2cap_run();
+    }
+}
+
+static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
+    
+    // log_info("l2cap_handle_connection_request for handle %u, psm %u cid %u\n", handle, psm, source_cid);
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) {
+        // 0x0002 PSM not supported
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002);
+        return;
+    }
+    
+    hci_connection_t * hci_connection = connection_for_handle( handle );
+    if (!hci_connection) {
+        // 
+        log_error("no hci_connection for handle %u\n", handle);
+        return;
+    }
+    // alloc structure
+    // log_info("l2cap_handle_connection_request register channel\n");
+    l2cap_channel_t * channel = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!channel){
+        // 0x0004 No resources available
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004);
+        return;
+    }
+    
+    // fill in 
+    BD_ADDR_COPY(channel->address, hci_connection->address);
+    channel->psm = psm;
+    channel->handle = handle;
+    channel->connection = service->connection;
+    channel->packet_handler = service->packet_handler;
+    channel->local_cid  = l2cap_next_local_cid();
+    channel->remote_cid = source_cid;
+    channel->local_mtu  = service->mtu;
+    channel->remote_mtu = L2CAP_DEFAULT_MTU;
+    channel->packets_granted = 0;
+    channel->remote_sig_id = sig_id; 
+
+    // limit local mtu to max acl packet length
+    if (channel->local_mtu > l2cap_max_mtu()) {
+        channel->local_mtu = l2cap_max_mtu();
+    }
+    
+    // set initial state
+    channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
+    channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) channel);
+    
+    // emit incoming connection request
+    l2cap_emit_connection_request(channel);
+}
+
+void l2cap_accept_connection_internal(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+
+    channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
+
+    // process
+    l2cap_run();
+}
+
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
+    if (!channel) {
+        log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+    channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
+    channel->reason = reason;
+    l2cap_run();
+}
+
+void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
+
+    channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+
+    // accept the other's configuration options
+    uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+    uint16_t pos     = 8;
+    while (pos < end_pos){
+        uint8_t type   = command[pos++];
+        uint8_t length = command[pos++];
+        // MTU { type(8): 1, len(8):2, MTU(16) }
+        if ((type & 0x7f) == 1 && length == 2){
+            channel->remote_mtu = READ_BT_16(command, pos);
+            // log_info("l2cap cid %u, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
+        }
+        pos += length;
+    }
+}
+
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
+    // log_info("l2cap_channel_ready_for_open 0x%02x\n", channel->state_var);
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
+    return 1;
+}
+
+
+void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
+
+    uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    uint16_t result = 0;
+    
+    log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state);
+    
+    // handle DISCONNECT REQUESTS seperately
+    if (code == DISCONNECTION_REQUEST){
+        switch (channel->state){
+            case L2CAP_STATE_CONFIG:
+            case L2CAP_STATE_OPEN:
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+            case L2CAP_STATE_WAIT_DISCONNECT:
+                l2cap_handle_disconnect_request(channel, identifier);
+                break;
+
+            default:
+                // ignore in other states
+                break;
+        }
+        return;
+    }
+    
+    // @STATEMACHINE(l2cap)
+    switch (channel->state) {
+            
+        case L2CAP_STATE_WAIT_CONNECT_RSP:
+            switch (code){
+                case CONNECTION_RESPONSE:
+                    result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
+                    switch (result) {
+                        case 0:
+                            // successful connection
+                            channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+                            channel->state = L2CAP_STATE_CONFIG;
+                            channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                            break;
+                        case 1:
+                            // connection pending. get some coffee
+                            break;
+                        default:
+                            // channel closed
+                            channel->state = L2CAP_STATE_CLOSED;
+
+                            // map l2cap connection response result to BTstack status enumeration
+                            l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
+                            
+                            // drop link key if security block
+                            if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
+                                hci_drop_link_key_for_bd_addr(&channel->address);
+                            }
+                            
+                            // discard channel
+                            linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+                            btstack_memory_l2cap_channel_free(channel);
+                            break;
+                    }
+                    break;
+                    
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+
+        case L2CAP_STATE_CONFIG:
+            switch (code) {
+                case CONFIGURE_REQUEST:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    l2cap_signaling_handle_configure_request(channel, command);
+                    break;
+                case CONFIGURE_RESPONSE:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
+                    break;
+                default:
+                    break;
+            }
+            if (l2cap_channel_ready_for_open(channel)){
+                // for open:
+                channel->state = L2CAP_STATE_OPEN;
+                l2cap_emit_channel_opened(channel, 0);
+                l2cap_emit_credits(channel, 1);
+            }
+            break;
+            
+        case L2CAP_STATE_WAIT_DISCONNECT:
+            switch (code) {
+                case DISCONNECTION_RESPONSE:
+                    l2cap_finialize_channel_close(channel);
+                    break;
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+            
+        case L2CAP_STATE_CLOSED:
+            // @TODO handle incoming requests
+            break;
+            
+        case L2CAP_STATE_OPEN:
+            //@TODO: implement other signaling packets, e.g. re-configure
+            break;
+        default:
+            break;
+    }
+    // log_info("new state %u\n", channel->state);
+}
+
+
+void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
+    
+    // get code, signalind identifier and command len
+    uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    
+    // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST 
+    if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
+        return;
+    }
+
+    // general commands without an assigned channel
+    switch(code) {
+            
+        case CONNECTION_REQUEST: {
+            uint16_t psm =        READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            uint16_t source_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
+            l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
+            return;
+        }
+            
+        case ECHO_REQUEST:
+            l2cap_register_signaling_response(handle, code, sig_id, 0);
+            return;
+            
+        case INFORMATION_REQUEST: {
+            uint16_t infoType = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            l2cap_register_signaling_response(handle, code, sig_id, infoType);
+            return;
+        }
+            
+        default:
+            break;
+    }
+    
+    
+    // Get potential destination CID
+    uint16_t dest_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+    
+    // Find channel for this sig_id and connection handle
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->handle == handle) {
+            if (code & 1) {
+                // match odd commands (responses) by previous signaling identifier 
+                if (channel->local_sig_id == sig_id) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            } else {
+                // match even commands (requests) by local channel id
+                if (channel->local_cid == dest_cid) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
+        
+    // Get Channel ID
+    uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 
+    hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
+    
+    switch (channel_id) {
+            
+        case L2CAP_CID_SIGNALING: {
+            
+            uint16_t command_offset = 8;
+            while (command_offset < size) {                
+                
+                // handle signaling commands
+                l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
+                
+                // increment command_offset
+                command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+            }
+            break;
+        }
+            
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+            
+        default: {
+            // Find channel for this channel_id and connection handle
+            l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id);
+            if (channel) {
+                l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+        }
+    }
+    
+    l2cap_run();
+}
+
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            l2cap_event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            l2cap_acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
+void l2cap_finialize_channel_close(l2cap_channel_t *channel){
+    channel->state = L2CAP_STATE_CLOSED;
+    l2cap_emit_channel_closed(channel);
+    // discard channel
+    linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+    btstack_memory_l2cap_channel_free(channel);
+}
+
+l2cap_service_t * l2cap_get_service(uint16_t psm){
+    linked_item_t *it;
+    
+    // close open channels
+    for (it = (linked_item_t *) l2cap_services; it ; it = it->next){
+        l2cap_service_t * service = ((l2cap_service_t *) it);
+        if ( service->psm == psm){
+            return service;
+        };
+    }
+    return NULL;
+}
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu){
+    // check for alread registered psm 
+    // TODO: emit error event
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (service) {
+        log_error("l2cap_register_service_internal: PSM %u already registered\n", psm);
+        l2cap_emit_service_registered(connection, L2CAP_SERVICE_ALREADY_REGISTERED, psm);
+        return;
+    }
+    
+    // alloc structure
+    // TODO: emit error event
+    service = (l2cap_service_t *) btstack_memory_l2cap_service_get();
+    if (!service) {
+        log_error("l2cap_register_service_internal: no memory for l2cap_service_t\n");
+        l2cap_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, psm);
+        return;
+    }
+    
+    // fill in 
+    service->psm = psm;
+    service->mtu = mtu;
+    service->connection = connection;
+    service->packet_handler = packet_handler;
+
+    // add to services list
+    linked_list_add(&l2cap_services, (linked_item_t *) service);
+    
+    // enable page scan
+    hci_connectable_control(1);
+
+    // done
+    l2cap_emit_service_registered(connection, 0, psm);
+}
+
+void l2cap_unregister_service_internal(void *connection, uint16_t psm){
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) return;
+    linked_list_remove(&l2cap_services, (linked_item_t *) service);
+    btstack_memory_l2cap_service_free(service);
+    
+    // disable page scan when no services registered
+    if (!linked_list_empty(&l2cap_services)) return;
+    hci_connectable_control(0);
+}
+
+//
+void l2cap_close_connection(void *connection){
+    linked_item_t *it;
+    
+    // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks
+    l2cap_channel_t * channel;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        channel = (l2cap_channel_t *) it;
+        if (channel->connection == connection) {
+            channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+        }
+    }   
+    
+    // unregister services
+    it = (linked_item_t *) &l2cap_services;
+    while (it->next) {
+        l2cap_service_t * service = (l2cap_service_t *) it->next;
+        if (service->connection == connection){
+            it->next = it->next->next;
+            btstack_memory_l2cap_service_free(service);
+        } else {
+            it = it->next;
+        }
+    }
+    
+    // process
+    l2cap_run();
+}
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id) {
+    switch(channel_id){
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            attribute_protocol_packet_handler = packet_handler;
+            break;
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            security_protocol_packet_handler = packet_handler;
+            break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap.h
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#pragma once
+
+#include "hci.h"
+#include "l2cap_signaling.h"
+#include <btstack/utils.h>
+#include <btstack/btstack.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+#define L2CAP_SIG_ID_INVALID 0
+
+#define L2CAP_HEADER_SIZE 4
+
+// size of HCI ACL + L2CAP Header for regular data packets (8)
+#define COMPLETE_L2CAP_HEADER (HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE)
+    
+// minimum signaling MTU
+#define L2CAP_MINIMAL_MTU 48
+#define L2CAP_DEFAULT_MTU 672
+    
+// check L2CAP MTU
+#if (L2CAP_MINIMAL_MTU + L2CAP_HEADER_SIZE) > HCI_ACL_PAYLOAD_SIZE
+#error "HCI_ACL_PAYLOAD_SIZE too small for minimal L2CAP MTU of 48 bytes"
+#endif    
+    
+// L2CAP Fixed Channel IDs    
+#define L2CAP_CID_SIGNALING                 0x0001
+#define L2CAP_CID_CONNECTIONLESS_CHANNEL    0x0002
+#define L2CAP_CID_ATTRIBUTE_PROTOCOL        0x0004
+#define L2CAP_CID_SIGNALING_LE              0x0005
+#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
+    
+void l2cap_init(void);
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason);
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid);
+uint16_t l2cap_max_mtu(void);
+
+void l2cap_block_new_credits(uint8_t blocked);
+int  l2cap_can_send_packet_now(uint16_t local_cid);    // non-blocking UART write
+
+// get outgoing buffer and prepare data
+uint8_t *l2cap_get_outgoing_buffer(void);
+
+int  l2cap_send_prepared(uint16_t local_cid, uint16_t len);
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len);
+
+int  l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len);
+int  l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len);
+    
+void l2cap_close_connection(void *connection);
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu);
+void l2cap_unregister_service_internal(void *connection, uint16_t psm);
+
+void l2cap_accept_connection_internal(uint16_t local_cid);
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason);
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id);
+
+
+// private structs
+typedef enum {
+    L2CAP_STATE_CLOSED = 1,           // no baseband
+    L2CAP_STATE_WILL_SEND_CREATE_CONNECTION,
+    L2CAP_STATE_WAIT_CONNECTION_COMPLETE,
+    L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT,
+    L2CAP_STATE_WAIT_CONNECT_RSP, // from peer
+    L2CAP_STATE_CONFIG,
+    L2CAP_STATE_OPEN,
+    L2CAP_STATE_WAIT_DISCONNECT,  // from application
+    L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT,   
+    L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST,
+    L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE,
+} L2CAP_STATE;
+
+typedef enum {
+    L2CAP_CHANNEL_STATE_VAR_NONE          = 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
+} L2CAP_CHANNEL_STATE_VAR;
+
+// info regarding an actual coneection
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    L2CAP_STATE state;
+    L2CAP_CHANNEL_STATE_VAR state_var;
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    
+    uint8_t   remote_sig_id;    // used by other side, needed for delayed response
+    uint8_t   local_sig_id;     // own signaling identifier
+    
+    uint16_t  local_cid;
+    uint16_t  remote_cid;
+    
+    uint16_t  local_mtu;
+    uint16_t  remote_mtu;
+    
+    uint16_t  psm;
+    
+    uint8_t   packets_granted;    // number of L2CAP/ACL packets client is allowed to send
+    
+    uint8_t   reason; // used in decline internal
+    
+    // client connection
+    void * connection;
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_channel_t;
+
+// info regarding potential connections
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // service id
+    uint16_t  psm;
+    
+    // incoming MTU
+    uint16_t mtu;
+    
+    // client connection
+    void *connection;    
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_service_t;
+
+
+typedef struct l2cap_signaling_response {
+    hci_con_handle_t handle;
+    uint8_t  sig_id;
+    uint8_t  code;
+    uint16_t data; // infoType for INFORMATION REQUEST, result for CONNECTION request
+} l2cap_signaling_response_t;
+    
+    
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap_signaling.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include "l2cap_signaling.h"
+
+#include <string.h>
+
+static char *l2cap_signaling_commands_format[] = {
+"D",    // 0x01 command reject: reason {cmd not understood (0), sig MTU exceeded (2:max sig MTU), invalid CID (4:req CID)}, data len, data
+"22",   // 0x02 connection request: PSM, Source CID
+"2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
+"22D",  // 0x04 config request: Dest CID, Flags, Configuration options
+"222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
+"22",   // 0x06 disconection request: Dest CID, Source CID
+"22",   // 0x07 disconection response: Dest CID, Source CID
+"D",    // 0x08 echo request: Data
+"D",    // 0x09 echo response: Data
+"2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
+"22D",  // 0x0b information response: InfoType, Result, Data
+};
+
+uint8_t   sig_seq_nr  = 0xff;
+uint16_t  source_cid  = 0x40;
+
+uint8_t l2cap_next_sig_id(void){
+    if (sig_seq_nr == 0xff) {
+        sig_seq_nr = 1;
+    } else {
+        sig_seq_nr++;
+    }
+    return sig_seq_nr;
+}
+
+uint16_t l2cap_next_local_cid(void){
+    return source_cid++;
+}
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 6 - L2CAP channel = 1
+    bt_store_16(acl_buffer, 6, 1);
+    // 8 - Code
+    acl_buffer[8] = cmd;
+    // 9 - id (!= 0 sequentially)
+    acl_buffer[9] = identifier;
+    
+    // 12 - L2CAP signaling parameters
+    uint16_t pos = 12;
+    const char *format = l2cap_signaling_commands_format[cmd-1];
+    uint16_t word;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+                word = va_arg(argptr, int);
+                // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                acl_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    acl_buffer[pos++] = word >> 8;
+                }
+                break;
+            case 'D': // variable data. passed: len, ptr
+                word = va_arg(argptr, int);
+                ptr  = va_arg(argptr, uint8_t *);
+                memcpy(&acl_buffer[pos], ptr, word);
+                pos += word;
+                break;
+            default:
+                break;
+        }
+        format++;
+    };
+    va_end(argptr);
+    
+    // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
+    // - the l2cap payload length is counted after the following channel id (only payload) 
+    
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  pos - 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  pos - 6 - 2);
+    // 10 - L2CAP signaling parameter length
+    bt_store_16(acl_buffer, 10, pos - 12);
+    
+    return pos;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/l2cap_signaling.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <btstack/utils.h>
+#include <btstack/hci_cmds.h>
+
+typedef enum {
+    COMMAND_REJECT = 1,
+    CONNECTION_REQUEST,
+    CONNECTION_RESPONSE,
+    CONFIGURE_REQUEST,
+    CONFIGURE_RESPONSE,
+    DISCONNECTION_REQUEST,
+    DISCONNECTION_RESPONSE,
+    ECHO_REQUEST,
+    ECHO_RESPONSE,
+    INFORMATION_REQUEST,
+    INFORMATION_RESPONSE
+} L2CAP_SIGNALING_COMMANDS;
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr);
+uint8_t  l2cap_next_sig_id(void);
+uint16_t l2cap_next_local_cid(void);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/linked_list.c	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/**
+ * interface to provide link key and remote name storage
+ */
+
+#pragma once
+
+#include <btstack/utils.h>
+
+typedef struct {
+
+    // management
+    void (*open)(void);
+    void (*close)(void);
+    
+    // link key
+    int  (*get_link_key)(bd_addr_t *bd_addr, link_key_t *link_key);
+    void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
+    void (*delete_link_key)(bd_addr_t *bd_addr);
+    
+    // remote name
+    int  (*get_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*delete_name)(bd_addr_t *bd_addr);
+
+    // persistent rfcomm channel
+    uint8_t (*persistent_rfcomm_channel)(char *servicename);
+
+} remote_device_db_t;
+
+extern remote_device_db_t remote_device_db_iphone;
+extern const remote_device_db_t remote_device_db_memory;
+
+// MARK: non-persisten implementation
+#include <btstack/linked_list.h>
+#define MAX_NAME_LEN 32
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    bd_addr_t bd_addr;
+} db_mem_device_t;
+
+typedef struct {
+    db_mem_device_t device;
+    link_key_t link_key;
+} db_mem_device_link_key_t;
+
+typedef struct {
+    db_mem_device_t device;
+    char device_name[MAX_NAME_LEN];
+} db_mem_device_name_t;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    char service_name[MAX_NAME_LEN];
+    uint8_t channel;
+} db_mem_service_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/remote_device_db_memory.c	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  run_loop.c
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#include <btstack/run_loop.h>
+
+#include <stdio.h>
+#include <stdlib.h>  // exit()
+
+#include "run_loop_private.h"
+
+#include "debug.h"
+#include "config.h"
+
+static run_loop_t * the_run_loop = NULL;
+
+extern const run_loop_t run_loop_embedded;
+
+#ifdef USE_POSIX_RUN_LOOP
+extern run_loop_t run_loop_posix;
+#endif
+
+#ifdef USE_COCOA_RUN_LOOP
+extern run_loop_t run_loop_cocoa;
+#endif
+
+// assert run loop initialized
+void run_loop_assert(void){
+#ifndef EMBEDDED
+    if (!the_run_loop){
+        log_error("ERROR: run_loop function called before run_loop_init!\n");
+        exit(10);
+    }
+#endif
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void run_loop_add_data_source(data_source_t *ds){
+    run_loop_assert();
+    the_run_loop->add_data_source(ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int run_loop_remove_data_source(data_source_t *ds){
+    run_loop_assert();
+    return the_run_loop->remove_data_source(ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void run_loop_add_timer(timer_source_t *ts){
+    run_loop_assert();
+    the_run_loop->add_timer(ts);
+}
+
+/**
+ * Remove timer from run loop
+ */
+int run_loop_remove_timer(timer_source_t *ts){
+    run_loop_assert();
+    return the_run_loop->remove_timer(ts);
+}
+
+void run_loop_timer_dump(){
+    run_loop_assert();
+    the_run_loop->dump_timer();
+}
+
+/**
+ * Execute run_loop
+ */
+void run_loop_execute() {
+    run_loop_assert();
+    the_run_loop->execute();
+}
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type){
+#ifndef EMBEDDED
+    if (the_run_loop){
+        log_error("ERROR: run loop initialized twice!\n");
+        exit(10);
+    }
+#endif
+    switch (type) {
+#ifdef EMBEDDED
+        case RUN_LOOP_EMBEDDED:
+            the_run_loop = (run_loop_t*) &run_loop_embedded;
+            break;
+#endif
+#ifdef USE_POSIX_RUN_LOOP
+        case RUN_LOOP_POSIX:
+            the_run_loop = &run_loop_posix;
+            break;
+#endif
+#ifdef USE_COCOA_RUN_LOOP
+        case RUN_LOOP_COCOA:
+            the_run_loop = &run_loop_cocoa;
+            break;
+#endif
+        default:
+#ifndef EMBEDDED
+            log_error("ERROR: invalid run loop type %u selected!\n", type);
+            exit(10);
+#endif
+            break;
+    }
+    the_run_loop->init();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/run_loop_embedded.c	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  run_loop_embedded.c
+ *
+ *  For this run loop, we assume that there's no global way to wait for a list
+ *  of data sources to get ready. Instead, each data source has to queried
+ *  individually. Calling ds->isReady() before calling ds->process() doesn't 
+ *  make sense, so we just poll each data source round robin.
+ *
+ *  To support an idle state, where an MCU could go to sleep, the process function
+ *  has to return if it has to called again as soon as possible
+ *
+ *  After calling process() on every data source and evaluating the pending timers,
+ *  the idle hook gets called if no data source did indicate that it needs to be
+ *  called right away.
+ *
+ */
+
+
+#include <btstack/run_loop.h>
+#include <btstack/linked_list.h>
+#include <btstack/hal_tick.h>
+#include <btstack/hal_cpu.h>
+
+#include "run_loop_private.h"
+#include "debug.h"
+
+#include <stddef.h> // NULL
+
+// the run loop
+static linked_list_t data_sources;
+
+static linked_list_t timers;
+
+#ifdef HAVE_TICK
+static uint32_t system_ticks;
+#endif
+
+static int trigger_event_received = 0;
+
+/**
+ * trigger run loop iteration
+ */
+void embedded_trigger(void){
+    trigger_event_received = 1;
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void embedded_add_data_source(data_source_t *ds){
+    linked_list_add(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int embedded_remove_data_source(data_source_t *ds){
+    return linked_list_remove(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void embedded_add_timer(timer_source_t *ts){
+#ifdef HAVE_TICK
+    linked_item_t *it;
+    for (it = (linked_item_t *) &timers; it->next ; it = it->next){
+        if (ts->timeout < ((timer_source_t *) it->next)->timeout) {
+            break;
+        }
+    }
+    ts->item.next = it->next;
+    it->next = (linked_item_t *) ts;
+    // log_info("Added timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    // embedded_dump_timer();
+#endif
+}
+
+/**
+ * Remove timer from run loop
+ */
+int embedded_remove_timer(timer_source_t *ts){
+#ifdef HAVE_TICK    
+    // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    return linked_list_remove(&timers, (linked_item_t *) ts);
+#else
+    return 0;
+#endif
+}
+
+void embedded_dump_timer(void){
+#ifdef HAVE_TICK
+#ifdef ENABLE_LOG_INFO 
+    linked_item_t *it;
+    int i = 0;
+    for (it = (linked_item_t *) timers; it ; it = it->next){
+        timer_source_t *ts = (timer_source_t*) it;
+        log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout);
+    }
+#endif
+#endif
+}
+
+/**
+ * Execute run_loop
+ */
+void embedded_execute(void) {
+    data_source_t *ds;
+
+    while (1) {
+
+        // process data sources
+        data_source_t *next;
+        for (ds = (data_source_t *) data_sources; ds != NULL ; ds = next){
+            next = (data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
+            ds->process(ds);
+        }
+        
+#ifdef HAVE_TICK
+        // process timers
+        while (timers) {
+            timer_source_t *ts = (timer_source_t *) timers;
+            if (ts->timeout > system_ticks) break;
+            run_loop_remove_timer(ts);
+            ts->process(ts);
+        }
+#endif
+        
+        // disable IRQs and check if run loop iteration has been requested. if not, go to sleep
+        hal_cpu_disable_irqs();
+        if (trigger_event_received){
+            hal_cpu_enable_irqs_and_sleep();
+            continue;
+        }
+        hal_cpu_enable_irqs();
+    }
+}
+
+#ifdef HAVE_TICK
+static void embedded_tick_handler(void){
+    system_ticks++;
+    trigger_event_received = 1;
+}
+
+uint32_t embedded_get_ticks(void){
+    return system_ticks;
+}
+
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms){
+    return time_in_ms / hal_tick_get_tick_period_in_ms();
+}
+
+// set timer
+void run_loop_set_timer(timer_source_t *ts, uint32_t timeout_in_ms){
+    uint32_t ticks = embedded_ticks_for_ms(timeout_in_ms);
+    if (ticks == 0) ticks++;
+    ts->timeout = system_ticks + ticks; 
+}
+#endif
+
+void embedded_init(void){
+
+    data_sources = NULL;
+
+#ifdef HAVE_TICK
+    timers = NULL;
+    system_ticks = 0;
+    hal_tick_init();
+    hal_tick_set_handler(&embedded_tick_handler);
+#endif
+}
+
+extern const run_loop_t run_loop_embedded;
+const run_loop_t run_loop_embedded = {
+    &embedded_init,
+    &embedded_add_data_source,
+    &embedded_remove_data_source,
+    &embedded_add_timer,
+    &embedded_remove_timer,
+    &embedded_execute,
+    &embedded_dump_timer
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BTstack/run_loop_private.h	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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	Mon Jun 09 09:03:25 2014 +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/F401RE-USBHost.lib	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/va009039/code/F401RE-USBHost/#b91fdea8c0a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KL46Z-USBHostBTstack/USBHostBTstack.cpp	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,187 @@
+// USBHostBTstack.cpp
+#include "USBHostBTstack.h"
+
+//#define BTSTACK_DEBUG
+
+#ifdef BTSTACK_DEBUG
+#define BT_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
+#define BT_DBG_BYTES(STR,BUF,LEN) _debug_bytes(__PRETTY_FUNCTION__,__LINE__,STR,BUF,LEN)
+#else
+#define BT_DBG(...)  while(0);
+#define BT_DBG_BYTES(S,BUF,LEN) while(0);
+#endif
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
+
+#define HCI_COMMAND_DATA_PACKET 0x01
+#define HCI_ACL_DATA_PACKET     0x02
+#define HCI_SCO_DATA_PACKET     0x03
+#define HCI_EVENT_PACKET        0x04
+
+USBHostBTstack::USBHostBTstack()
+{
+    host = USBHost::getHostInst();
+    init();
+    m_pCb = NULL;
+}
+
+void USBHostBTstack::init()
+{
+    BT_DBG("");
+    dev = NULL;
+    int_in = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    btstack_intf = -1;
+    btstack_device_found = false;
+    dev_connected = false;
+    ep_int_in = false;
+    ep_bulk_in = false;
+    ep_bulk_out = false;
+}
+
+bool USBHostBTstack::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostBTstack::connect()
+{
+    if (dev_connected) {
+        return true;
+    }
+ 
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            BT_DBG("Trying to connect BTstack device\r\n");
+            
+            if(host->enumerate(dev, this)) {
+                break;
+            }
+            if (btstack_device_found) {
+                int_in = dev->getEndpoint(btstack_intf, INTERRUPT_ENDPOINT, IN);
+                bulk_in = dev->getEndpoint(btstack_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(btstack_intf, BULK_ENDPOINT, OUT);
+                if (!int_in || !bulk_in || !bulk_out) {
+                    continue;
+                }
+                USB_INFO("New BTstack device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, btstack_intf);
+                //dev->setName("BTstack", btstack_intf);
+                //host->registerDriver(dev, btstack_intf, this, &USBHostBTstack::init);
+ 
+                //int_in->attach(this, &USBHostBTstack::int_rxHandler);
+                //host->interruptRead(dev, int_in, int_report, int_in->getSize(), false);
+ 
+                //bulk_in->attach(this, &USBHostBTstack::bulk_rxHandler);
+                //host->bulkRead(dev, bulk_in, bulk_report, bulk_in->getSize(), false);
+ 
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+/*virtual*/ void USBHostBTstack::setVidPid(uint16_t vid, uint16_t pid)
+{
+    BT_DBG("vid:%04x,pid:%04x", vid, pid);
+}
+ 
+/*virtual*/ bool USBHostBTstack::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    BT_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol);
+    if ((btstack_intf == -1) && intf_class == 0xe0) {
+        btstack_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+ 
+/*virtual*/ bool USBHostBTstack::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    BT_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir);
+    if (intf_nb == btstack_intf) {
+        if (ep_int_in == false && type == INTERRUPT_ENDPOINT && dir == IN) {
+            ep_int_in = true;
+        } else if (ep_bulk_in == false && type == BULK_ENDPOINT && dir == IN) {
+            ep_bulk_in = true;
+        } else if (ep_bulk_out == false && type == BULK_ENDPOINT && dir == OUT) {
+            ep_bulk_out = true;
+        } else {
+            return false;
+        }
+        if (ep_int_in && ep_bulk_in && ep_bulk_out) {
+            btstack_device_found = true;
+        }
+        return true;
+    }
+    return false;
+}
+ 
+int USBHostBTstack::open()
+{
+    BT_DBG("%p", this);
+    if (!connect()) {
+        error("Bluetooth not found.\n");
+    }
+    return 0;
+}
+
+int USBHostBTstack::send_packet(uint8_t packet_type, uint8_t* packet, int size)
+{
+    USB_TYPE res;
+    switch(packet_type){
+        case HCI_COMMAND_DATA_PACKET:
+            BT_DBG_BYTES("HCI_CMD:", packet, size);
+            res = host->controlWrite(dev,
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_DEVICE, 
+                    0, 0, 0, packet, size);
+            TEST_ASSERT(res == USB_TYPE_OK);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            BT_DBG_BYTES("ACL_SND:", packet, size);
+            res = host->bulkWrite(dev, bulk_out, packet, size);
+            TEST_ASSERT(res == USB_TYPE_OK);
+            break;
+        default:
+            TEST_ASSERT(0);
+    }
+    return 0;
+}
+
+void USBHostBTstack::register_packet_handler(void (*pMethod)(uint8_t, uint8_t*, uint16_t) )
+{
+    BT_DBG("pMethod: %p", pMethod);
+    m_pCb = pMethod;
+}
+
+void USBHostBTstack::poll()
+{
+    int result = host->interruptReadNB(int_in, int_report, sizeof(int_report));
+    if (result >= 0) {
+        int len = int_in->getLengthTransferred();
+        BT_DBG_BYTES("HCI_EVT:", int_report, len);
+        if (m_pCb) {
+            m_pCb(HCI_EVENT_PACKET, int_report, len);
+        }    
+    }
+    result = host->bulkReadNB(bulk_in, bulk_report, sizeof(bulk_report));
+    if (result >= 0) {
+        int len = bulk_in->getLengthTransferred();
+        BT_DBG_BYTES("HCI_ACL_RECV:", bulk_report, len);
+        if (m_pCb) {
+            m_pCb(HCI_ACL_DATA_PACKET, bulk_report, len);
+        }    
+    }
+}
+
+void _debug_bytes(const char* pretty, int line, const char* s, uint8_t* buf, int len)
+{
+    printf("[%s:%d]\n%s", pretty, line, s);
+    for(int i = 0; i < len; i++) {
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KL46Z-USBHostBTstack/USBHostBTstack.h	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,62 @@
+#include "USBHostConf.h"
+#include "USBHost.h"
+#pragma once
+
+#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+
+/** 
+ * A class to communicate a BTstack
+ */
+class USBHostBTstack : public IUSBEnumerator {
+public:
+    /**
+    * Constructor
+    *
+    */
+    USBHostBTstack();
+
+    /**
+    * Check if a BTstack device is connected
+    *
+    * @return true if a BTstack device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect to a BTstack device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    int open();
+    int send_packet(uint8_t packet_type, uint8_t* packet, int size);
+    void register_packet_handler( void (*pMethod)(uint8_t, uint8_t*, uint16_t));
+    void poll();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    uint8_t int_report[64];
+    uint8_t bulk_report[64];
+    USBEndpoint * int_in;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    bool ep_int_in;
+    bool ep_bulk_in;
+    bool ep_bulk_out;
+
+    bool btstack_device_found;
+    int btstack_intf;
+    void (*m_pCb)(uint8_t, uint8_t*, uint16_t);
+    void init();
+};
+
+void _debug_bytes(const char* pretty, int line, const char* s, uint8_t* buf, int len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,128 @@
+#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);
+
+#if defined(TARGET_NUCLEO_F401RE)
+DigitalOut led1(LED1);
+int led2 = 0;
+#define LED_ON  0
+#define LED_OFF 1
+#elif defined(TARGET_KL46Z)||defined(TARGET_KL25Z)
+DigitalOut led1(LED1), led2(LED2);
+#define LED_ON  0
+#define LED_OFF 1
+#else
+#error "target error" 
+#endif
+
+#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) ? LED_ON : LED_OFF; // left
+        led2 = (report[2] & 0x02) ? LED_ON : LED_OFF; // right
+        //led2 = (report[2] & 0x04) ? LED_ON : LED_OFF; // 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 = LED_OFF;
+    led2 = LED_OFF;
+    
+    // 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/0b3ab51c8877
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.cpp	Mon Jun 09 09:03:25 2014 +0000
@@ -0,0 +1,33 @@
+#include "mbed.h"
+#include "bd_addr.h"
+bd_addr::bd_addr()
+{
+
+}
+
+bd_addr::bd_addr(char* s)
+{
+    for(int i = 0; i <= 5; i++) {
+        ad[i] = strtol(s+i*3, NULL, 16);
+    }
+}
+
+uint8_t* bd_addr::data(uint8_t* addr)
+{
+    if (addr != NULL) {
+        ad[5] = addr[0];
+        ad[4] = addr[1];
+        ad[3] = addr[2];
+        ad[2] = addr[3];
+        ad[1] = addr[4];
+        ad[0] = addr[5];
+    }
+    return ad;
+}
+
+char* bd_addr::to_str()
+{
+    snprintf(ad_str, sizeof(ad_str), "%02X:%02X:%02X:%02X:%02X:%02X", 
+        ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
+    return ad_str;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.h	Mon Jun 09 09:03:25 2014 +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