Test version of BlueUSB stack. Includes SDP and RFCOMM. As Client it allows to connect to my fischertechnik TX Controller. As Server it echo\\\\\\\'s characters to Putty. PIN=1234

Dependencies:   mbed myUSBHost AvailableMemory

Dependents:   mbed_TANK_Kinect myBlueUSB_ros ftusbClass

Files at this revision

API Documentation at this revision

Comitter:
networker
Date:
Mon Apr 04 16:41:03 2011 +0000
Child:
1:0dde58e0cccf
Commit message:
initial revision

Changed in this revision

HCITransportUSB.h Show annotated file Show diff for this revision Revisions of this file
L2CAP.cpp Show annotated file Show diff for this revision Revisions of this file
Socket.cpp Show annotated file Show diff for this revision Revisions of this file
Socket.h Show annotated file Show diff for this revision Revisions of this file
Utils.cpp Show annotated file Show diff for this revision Revisions of this file
Utils.h Show annotated file Show diff for this revision Revisions of this file
hci.cpp Show annotated file Show diff for this revision Revisions of this file
hci.h Show annotated file Show diff for this revision Revisions of this file
hci_private.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HCITransportUSB.h	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,46 @@
+#ifndef HCITRANSPORTUSB_H
+#define HCITRANSPORTUSB_H
+#define MAX_HCL_SIZE 260
+#define MAX_ACL_SIZE 400
+#include "USBHost.h"
+
+extern int bulk;
+
+class HCITransportUSB : public HCITransport {
+    int _device;
+    u8* _hciBuffer;
+    u8* _aclBuffer;
+
+public:
+    void Open(int device, u8* hciBuffer, u8* aclBuffer) {
+        _device = device;
+        _hciBuffer = hciBuffer;
+        _aclBuffer = aclBuffer;
+        USBInterruptTransfer(_device,0x81,_hciBuffer,MAX_HCL_SIZE,HciCallback,this);
+        USBBulkTransfer(_device,0x82,_aclBuffer,MAX_ACL_SIZE,AclCallback,this);
+    }
+
+    static void HciCallback(int device, int endpoint, int status, u8* data, int len, void* userData) { 
+        HCI* t = ((HCITransportUSB*)userData)->_target;
+        if (t)
+            t->HCIRecv(data,len);
+        USBInterruptTransfer(device,0x81,data,MAX_HCL_SIZE,HciCallback,userData);
+    }
+
+    static void AclCallback(int device, int endpoint, int status, u8* data, int len, void* userData) { 
+        HCI* t = ((HCITransportUSB*)userData)->_target; //printf("ACL: %d bytes avail\n", len);
+        if (t)
+            t->ACLRecv(data,len);
+        USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData);
+    }
+
+    virtual void HCISend(const u8* data, int len) {
+        USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len);
+    }
+
+    virtual void ACLSend(const u8* data, int len) {
+        USBBulkTransfer(_device,0x02,(u8*)data,len);
+    }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/L2CAP.cpp	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,569 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+#include "HCITransportUSB.h"
+
+#define L2CAP_COMMAND_REJ       0x01
+#define L2CAP_CONN_REQ          0x02
+#define L2CAP_CONN_RSP          0x03
+#define L2CAP_CONF_REQ          0x04
+#define L2CAP_CONF_RSP          0x05
+#define L2CAP_DISCONN_REQ       0x06
+#define L2CAP_DISCONN_RSP       0x07
+#define L2CAP_ECHO_REQ          0x08
+#define L2CAP_ECHO_RSP          0x09
+#define L2CAP_INFO_REQ          0x0a
+#define L2CAP_INFO_RSP          0x0b
+
+//template <class T> T min(T a, T b) { return a<b ? a : b;}
+
+/* L2CAP command codes */
+const char* L2CAP_ComandCodeStr(int c) {
+    switch (c) {
+        case L2CAP_COMMAND_REJ:
+            return "L2CAP_COMMAND_REJ";
+        case L2CAP_CONN_REQ:
+            return "L2CAP_CONN_REQ";
+        case L2CAP_CONN_RSP:
+            return "L2CAP_CONN_RSP";
+        case L2CAP_CONF_REQ:
+            return "L2CAP_CONF_REQ";
+        case L2CAP_CONF_RSP:
+            return "L2CAP_CONF_RSP";
+        case L2CAP_DISCONN_REQ:
+            return "L2CAP_DISCONN_REQ";
+        case L2CAP_DISCONN_RSP:
+            return "L2CAP_DISCONN_RSP";
+        case L2CAP_ECHO_REQ:
+            return "L2CAP_ECHO_REQ";
+        case L2CAP_ECHO_RSP:
+            return "L2CAP_ECHO_RSP";
+        case L2CAP_INFO_REQ:
+            return "L2CAP_INFO_REQ";
+        case L2CAP_INFO_RSP:
+            return "L2CAP_INFO_RSP";
+    }
+    return "unknown";
+}
+
+#define OFFSET  8 //means the buffer also has space for the l2cap/hci headers and need not be allocated and copied
+//#define OFFSET  0 //means the buffer only has space for the payload which need to be copied
+#if OFFSET == 0
+#define L2CAPBUFSIZE    128
+#else
+#define L2CAPBUFSIZE    0
+#endif
+
+typedef struct {
+    u16    handle;
+    u16    length;            // total
+    u16    l2capLength;    // length -4
+    u16    cid;            // Signaling packet CID = 1
+    u8  data[L2CAPBUFSIZE];       // Largest thing to send!!! todo
+} L2CAPData;
+
+//
+void BTDevice::Init() {
+    memset(&_info,0,sizeof(inquiry_info));
+    _handle = 0;
+    _name[0] = 0;
+    _state = 0;
+}
+
+// virtual SocketHandler
+int BTDevice::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+    L2CAPSocket* s = (L2CAPSocket*)sock;
+    L2CAPAddr* a = (L2CAPAddr*)addr;
+    s->scid = 0x40 + sock->ID-1;   // are these reserved?
+    s->dcid = 0;
+    Connect(s->scid,a->psm);
+    sock->State = SocketState_L2CAP_WaitConnectRsp;
+    contState = 0;
+    return sock->ID;
+}
+
+// virtual SocketHandler, called from HCI which is ABOVE L2CAP
+int BTDevice::Send(SocketInternal* sock, const u8* data, int len) {
+    L2CAPSocket* s = (L2CAPSocket*)sock;
+#if OFFSET == 8  //sizeof L2CAPData header
+    L2CAPData &d = *const_cast<L2CAPData*>((L2CAPData*)data);
+#else
+    L2CAPData d;
+#endif
+    if (len > peer_mtu) {//mtu concerns the l2cap mtu, because we use basic mode we cannot segment
+        printf("MTU (%d) for outgoing packet (%d) exceeded\n", peer_mtu, len);
+        return 0;
+    }
+    d.handle = _handle | 0x2000;
+    d.length = 4 + len - OFFSET;
+    d.l2capLength = len - OFFSET;
+    d.cid = s->dcid;
+    printf("cid=%d: ", d.cid);
+    printfBytes("sending: ", data, len);
+
+#if OFFSET == 0
+    if (len > L2CAPBUFSIZE)
+        return -1;
+    memcpy(d.data,data,len);
+    return Send((u8*)&d,len+8);
+#else
+    return Send(data, len);
+#endif
+}
+
+// virtual SocketHandler
+int BTDevice::Close(SocketInternal* sock) {
+    printf("L2CAP close %d\n",sock->ID);
+    sock->State = SocketState_L2CAP_WaitDisconnect;
+    L2CAPSocket* s = (L2CAPSocket*)sock;
+    return Disconnect(s->scid,s->dcid);
+}
+
+L2CAPSocket* BTDevice::SCIDToSocket(int scid) {
+    return (L2CAPSocket*)GetSocketInternal(scid-0x40+1);
+}
+
+int BTDevice::Send(const u8* data, int len) {//printfBytes("Transport : ", data, len);
+    _transport->ACLSend(data,len);
+    return 0;
+}
+
+void BTDevice::repeat_cmd() {
+printf("Cmd on handle %#x timed out, resending txid=%d\n", _handle, last_req.id);
+  Send ((u8*)&last_req, last_req.length+4);//danger! interrupt context, Send is not reentrant
+  //optionally set new larger timeout
+}
+
+int BTDevice::Send(u8 c, u8 id, u16* params, int count) {
+    L2CAPCmd cmd;
+    cmd.handle = _handle | 0x2000;
+    cmd.length = 8 + count*2;
+
+    cmd.l2capLength = cmd.length-4;
+    cmd.cid = 1;    // Signaling packet
+
+    cmd.cmd = c;
+    cmd.id = id;
+    cmd.cmdLength = count*2;
+    for (int i = 0; i < count; i++)
+        cmd.params[i] = params[i];
+    if ((c & 1) == 0) { //this is a request
+       last_req = cmd;
+       rtx.attach(this, &BTDevice::repeat_cmd, 5.0);
+       printf("Starting timeout for %#x, txid=%d\n", _handle, id);
+    }
+    return Send((u8*)&cmd,cmd.length+4);
+}
+
+int BTDevice::Connect(int scid, int psm) {
+    u16 p[2];
+    p[0] = psm;
+    p[1] = scid;
+    return Send(L2CAP_CONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::Disconnect(int scid, int dcid) {
+    u16 p[2];
+    p[0] = dcid;
+    p[1] = scid;
+    return Send(L2CAP_DISCONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::ConfigureRequest(int dcid) {
+    u16 p[4];
+    p[0] = dcid;
+    p[1] = 0;
+    p[2] = 0x0201;  // Options
+    p[3] = min(0x02A0, MAX_ACL_SIZE);  // my receiving MTU 672
+    return Send(L2CAP_CONF_REQ,_txid++,p,4);
+}
+
+int BTDevice::ConfigureResponse(u8 rxid, int dcid) {
+    u16 p[3];
+    p[0] = dcid; //source cid
+    p[1] = 0;    //flags  (no continuation)
+    p[2] = 0;    //result (success)
+    return Send(L2CAP_CONF_RSP,rxid,p,3);
+}
+
+int BTDevice::DisconnectResponse(u8 rxid, int scid, int dcid) {
+    u16 p[2];
+    p[0] = dcid;
+    p[1] = scid;
+    return Send(L2CAP_DISCONN_RSP,rxid,p,2);
+}
+#if 0
+//handle16, length16, lengthL2CAP16, cid16, code8, tid8, lengthData16
+// 0, 1,     2, 3,     4, 5,         6, 7,   8,    9,     10, 11
+void BTDevice::Control(const u8* data, int len) { //control channel receive
+    printf("\x1B[%dm", 31);
+    int cc = data[8];//command code
+    printf(L2CAP_ComandCodeStr(cc));
+    //int result = LE16(data+16);//conn_rsp, and conf_resp only
+    //printf(" Result %d\n",result);
+    switch (cc) {
+        case L2CAP_COMMAND_REJ://bad command, eg. MTU, check (reason)
+            printf(" rejection reason=%d\n", LE16(data+12));
+            break;
+        case L2CAP_CONN_REQ://incoming connection request, not expected but should reply with proper rejection (or accept)
+            //when a connection is accepted a new socket must be opened
+            break;
+            // Response to our initial connect from Remote
+        case L2CAP_CONN_RSP: {
+            int dcid = LE16(data+12);
+            int scid = LE16(data+14);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            int result = LE16(data+16);
+            printf("Result=%d, Status = %d\n", result, LE16(data+18));
+            if (s->si.State != SocketState_L2CAP_WaitConnectRsp) {
+                printf("Unexpected event ignored\n");
+                break;
+            }
+            if (result == 0) {
+                if (s) {
+                    s->si.State = SocketState_L2CAP_Config_wait;
+                    s->dcid = dcid;
+                    ConfigureRequest(dcid);
+                    s->si.State = SocketState_L2CAP_Config_wait_reqrsp;
+                    printf("Sent ConfigureRequest, state=WAIT_CONFIG_REQ-RSP\n");
+                }
+            } else {
+                s->si.SetState(SocketState_Closed);
+                printf("Connect failed?\n");
+            }
+        }
+        break;
+
+        case L2CAP_CONF_RSP: {
+            int result = LE16(data+16);
+            printf("Result=%d, datalen=%d, %smore conf to follow\n", result, LE16(data+10), LE16(data+14)?"":"No ");
+            //should parse the config
+            printfBytes("CONF RSP:", data+8, LE16(data+10)+4);
+            int scid = LE16(data+12);
+            SocketInternal* s = (SocketInternal*)SCIDToSocket(scid);
+            if (s == 0) break;
+            if (s->State != SocketState_L2CAP_Config_wait_reqrsp && s->State != SocketState_L2CAP_Config_wait_rsp) {
+                printf("Unexpected event ignored\n");
+                break;
+            }
+            if (result == 0) { //configuration acceptable
+                if (s->State == SocketState_L2CAP_Config_wait_reqrsp) {
+                    s->State = SocketState_L2CAP_Config_wait_req;
+                    printf("State=WAIT_CONFIG_REQ\n");
+                } else {
+                    ConfigureResponse(data[9],((L2CAPSocket*)s)->dcid);//data[9]==txid
+                    printf("Sent ConfigureResponse, state=Open\n");
+                    s->SetState(SocketState_Open);
+                }
+            } else {
+                printf("Renegotiate configuration\n");
+            }
+        }
+        break;
+
+        case L2CAP_CONF_REQ: {
+            int scid = LE16(data+12);//flags (data[14] LSB is continuation flag, data[18],[19] are the MTU
+            L2CAPSocket* s = SCIDToSocket(scid);
+            printfBytes("CONF REQ: ", data+8, LE16(data+10)+4);//data+16 contains option type 1-4 1=MTU, 2=flush timeout, 3=QoS, 4=FCM
+            if (s == 0) break;
+            if (s->si.State == SocketState_Closed ||
+                    s->si.State == SocketState_L2CAP_WaitConnectRsp ||
+                    s->si.State == SocketState_L2CAP_WaitDisconnect) {
+                //Send Reject command
+                break;
+            }
+            switch (data[16]) {
+                case 1:
+                    peer_mtu = LE16(data+18);
+                    printf("MTU = %d bytes\n", peer_mtu);
+                    break;
+                default:
+                    printf("Unsupported configuration option %d, value = %#X\n", data[16], LE16(data+18));
+                    break;
+            }
+            if (1 /* options acceptable */) {
+                printf("Sending ConfigureResponse, old state=%d ", s->si.State);
+                ConfigureResponse(data[9],s->dcid);//data[9]==txid, success
+                switch (s->si.State) {
+                    case SocketState_L2CAP_Config_wait:
+                        s->si.State = SocketState_L2CAP_Config_wait_send;
+                        break;
+                    case SocketState_L2CAP_Config_wait_req:
+                        ((SocketInternal*)s)->SetState(SocketState_Open);
+                        break;
+                    case SocketState_L2CAP_Config_wait_rsp:
+                        break;
+                    case SocketState_L2CAP_Config_wait_reqrsp:
+                        s->si.State = SocketState_L2CAP_Config_wait_rsp;
+                        break;
+                }
+                printf("new state=%d\n", s->si.State);
+            } else { //options not acceptable
+                ConfigureResponse(data[9],s->dcid);//indicates success but should indicate fail
+            }
+        }
+        break;
+        case L2CAP_DISCONN_REQ:  {
+            int dcid = LE16(data+12);
+            int scid = LE16(data+14);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            s->si.SetState(SocketState_Closed);
+            DisconnectResponse(data[9], scid, dcid);
+        }
+        break;
+        case L2CAP_DISCONN_RSP: {
+            int scid = LE16(data+14);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            if (s->si.State == SocketState_L2CAP_WaitDisconnect)
+                s->si.SetState(SocketState_Closed);
+        }
+        break;
+    }
+    printf("\x1b[0m");
+}
+#else
+//code8, tid8, lengthData16
+//   0,    1,     2, 3
+void BTDevice::Control(const u8* data, int len) { //control channel receive
+    printf("\x1B[%dm", 31);
+    int cc = data[0];//command code
+    if (cc & 1) { //it is a response or a reject
+      rtx.detach(); //kill the timeout
+      printf("timeout cancelled for handle %#x, txid=%d\n", _handle, data[1]);
+    }
+    printf(L2CAP_ComandCodeStr(cc));
+    switch (cc) {
+        case L2CAP_COMMAND_REJ://bad command, eg. MTU, check (reason)
+            printf(" rejection reason=%d\n", LE16(data+4));
+            break;
+        case L2CAP_CONN_REQ://incoming connection request, not expected but should reply with proper rejection (or accept)
+            //when a connection is accepted a new socket must be opened
+            printf("Remote side requested a connection\n");
+            break;
+            // Response to our initial connect from Remote
+        case L2CAP_CONN_RSP: {
+            int dcid = LE16(data+4);
+            int scid = LE16(data+6);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            int result = LE16(data+10);
+            printf(" Result=%d, Status = %d\n", result, LE16(data+10));
+            if (s->si.State != SocketState_L2CAP_WaitConnectRsp) {
+                printf("Unexpected event ignored\n");
+                break;
+            }
+            if (result == 0) {
+                if (s) {
+                    s->si.State = SocketState_L2CAP_Config_wait;
+                    s->dcid = dcid;
+                    ConfigureRequest(dcid);
+                    s->si.State = SocketState_L2CAP_Config_wait_reqrsp;
+                    printf("Sent ConfigureRequest, state=WAIT_CONFIG_REQ_RSP\n");
+                }
+            } else {
+                s->si.SetState(SocketState_Closed);
+                printf("Connect failed?\n");
+            }
+        }
+        break;
+
+        case L2CAP_CONF_RSP: {
+            int result = LE16(data+8);
+            printf("Result=%d, datalen=%d, %smore conf to follow\n", result, LE16(data+2), LE16(data+6)?"":"No ");
+            //should parse the config
+            printfBytes("CONF RSP:", data, LE16(data+2)+4);
+            int scid = LE16(data+4);
+            SocketInternal* s = (SocketInternal*)SCIDToSocket(scid);
+            if (s == 0) break;
+            if (s->State != SocketState_L2CAP_Config_wait_reqrsp && s->State != SocketState_L2CAP_Config_wait_rsp) {
+                printf("Unexpected event ignored\n");
+                break;
+            }
+            if (result == 0) { //configuration acceptable
+                if (s->State == SocketState_L2CAP_Config_wait_reqrsp) {
+                    s->State = SocketState_L2CAP_Config_wait_req;
+                    printf("State=WAIT_CONFIG_REQ\n");
+                } else {
+                    ConfigureResponse(data[1],((L2CAPSocket*)s)->dcid);//data[1]==txid
+                    printf("Sent ConfigureResponse, state=Open\n");
+                    s->SetState(SocketState_Open);
+                }
+            } else {
+                printf("Renegotiate configuration\n");
+            }
+        }
+        break;
+
+        case L2CAP_CONF_REQ: {
+            int scid = LE16(data+4);//flags (data[6] LSB is continuation flag, data[10],[11] are the MTU
+            L2CAPSocket* s = SCIDToSocket(scid);
+            printfBytes("CONF REQ: ", data, LE16(data+2)+4);//data+8 contains option type 1-4 1=MTU, 2=flush timeout, 3=QoS, 4=FCM
+            if (s == 0) break;
+            if (s->si.State == SocketState_Closed ||
+                    s->si.State == SocketState_L2CAP_WaitConnectRsp ||
+                    s->si.State == SocketState_L2CAP_WaitDisconnect) {
+                //Send Reject command
+                break;
+            }
+            switch (data[8]) {
+                case 1:
+                    peer_mtu = LE16(data+10);
+                    printf("MTU = %d bytes\n", peer_mtu);
+                    break;
+                default:
+                    printf("Unsupported configuration option %d, value = %#X\n", data[8], LE16(data+10));
+                    break;
+            }
+            if (1 /* options acceptable */) {
+                printf("Sending ConfigureResponse, old state=%d ", s->si.State);
+                ConfigureResponse(data[1],s->dcid);//data[1]==txid, success
+                switch (s->si.State) {
+                    case SocketState_L2CAP_Config_wait:
+                        s->si.State = SocketState_L2CAP_Config_wait_send;
+                        break;
+                    case SocketState_L2CAP_Config_wait_req:
+                        ((SocketInternal*)s)->SetState(SocketState_Open);
+                        break;
+                    case SocketState_L2CAP_Config_wait_rsp:
+                        break;
+                    case SocketState_L2CAP_Config_wait_reqrsp:
+                        s->si.State = SocketState_L2CAP_Config_wait_rsp;
+                        break;
+                }
+                printf("new state=%d\n", s->si.State);
+            } else { //options not acceptable
+                ConfigureResponse(data[1],s->dcid);//indicates success but should indicate fail
+            }
+        }
+        break;
+        case L2CAP_DISCONN_REQ:  {
+            int dcid = LE16(data+4);
+            int scid = LE16(data+6);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            s->si.SetState(SocketState_Closed);
+            DisconnectResponse(data[1], scid, dcid);
+        }
+        break;
+        case L2CAP_DISCONN_RSP: {
+            int scid = LE16(data+6);
+            L2CAPSocket* s = SCIDToSocket(scid);
+            if (s->si.State == SocketState_L2CAP_WaitDisconnect)
+                s->si.SetState(SocketState_Closed);
+        }
+        break;
+        default: printf("Unsupported L2CAP message %d\n", cc);
+    }
+    printf("\x1b[0m");
+}
+#endif
+
+void BTDevice::ACLFwd(const u8* data, int len) {
+    if (l2cap_sock == 1) {
+        //printf("cannot handle segmented ACL control packets\n");
+        Control(data, len);
+        return;
+    }
+    SocketInternal* s = (SocketInternal*)SCIDToSocket(l2cap_sock);
+    if (s)
+        s->Recv(data,len);
+    else
+        printf("Bad event cid %d\n",l2cap_sock);
+}
+//sometimes acl packets are segmented, in that case the l2cap payload length does not correspond to the acl pkt length
+//and the l2cap packet length. L2CAP works in basic mode and cannot be segmented hence the l2cap pkt size corresponds to
+//the acl pkt size
+void BTDevice::ACLRecv(const u8* data, int acllen) {
+    printfBytes("L2CP",data,acllen);
+    u16 handle = LE16(data);
+    if ((handle&0x0fff) !=  _handle) {
+        printf("unexpected handle %#x, this _handle=%#x\n", handle, _handle);
+        return;
+    }
+    char pb = (handle>>12) & 3;
+    int p = 4; //start of l2cap packet
+    int len = LE16(data+2); //length of l2cap pkt
+    while (p < len)
+        switch (contState) {
+            case 0:
+                plen = data[p++];
+                contState = 1;
+                break;
+            case 1:
+                plen += data[p++]<<8;
+                if (pb == 2 && plen == acllen-8) {//normal case, l2cap pkt is contained completely in this hci pkt
+                    l2cap_sock = data[p] + (data[p+1]<<8);
+                    contState = 0;
+                    ACLFwd(data+8, plen); //forward the packet in its original buffer
+                    return; //all data was dealt with
+                } else { //packet is segmented
+                printf("ACL packet is segmented\n");
+                    contState = 2;
+                    contBuf = new unsigned char[plen];//allocate recombination buffer
+                    contPos = 0;
+                }
+                break;
+            case 2:
+                l2cap_sock = data[p++];
+                contState = 3;
+                break;
+            case 3:
+                l2cap_sock += data[p++]<<8;
+                contState = 4;
+                break;
+            case 4: //data, recombine segmented ACL (not l2cap!) frames
+                if (contPos < plen) {//buffer not yet full
+                    int datalen = acllen - p; //data in this incoming pkt
+                    int remcap = plen - contPos; //remaining capacity in the recombination buffer
+                    if (datalen <= remcap) {
+                        memcpy(contBuf+contPos, data+p, datalen);
+                        contPos += datalen;
+                        p = acllen;//end of data, stop the while loop
+                        if (contPos == plen) {//buffer is full now
+                printfBytes("Recombined packet is:", contBuf, plen);
+                            ACLFwd(contBuf, plen); //forward the recombination buffer
+                            delete[] contBuf;//and free the buffer
+                            contState = 0;
+                        }//else stay in this state to wait for the rest
+                    } else {//data contains (part of) next packet
+                        memcpy(contBuf+contPos, data+p, plen-contPos);//this packet is complete
+                        p += plen-contPos;
+                printfBytes("Recombined packet is:", contBuf, plen);
+                printfBytes("Next packet starts with:", data+p, acllen-p);
+                        ACLFwd(contBuf, plen); //forward the recombination buffer
+                        delete[] contBuf;//and free the buffer
+                        contState = 0; //continue with the next packet
+                    }
+                } else {
+                    printf("Cannot append to buffer (size=%d, pos=%d, datalen = %d)\n", plen, contPos, len-p);
+                    contState = 0;
+                    return;
+                }
+                break;
+        }//switch (and while)
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.cpp	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "Socket.h"
+
+#define MAX_SOCKET_HANDLERS 4
+#define MAX_SOCKETS 16
+
+class SocketInternalPad
+{
+    public:
+    SocketInternal si;
+    u8  pad[8];
+};
+
+class SocketManager
+{
+    SocketHandler*  _handlers[MAX_SOCKET_HANDLERS];
+    SocketInternalPad  _sockets[MAX_SOCKETS];
+
+    public:
+    SocketManager()
+    {
+        memset(_handlers,0,sizeof(_handlers));
+        memset(_sockets,0,sizeof(_sockets));
+    }
+
+    SocketHandler* GetHandler(int type)
+    {
+        if (type < 1 || type > MAX_SOCKET_HANDLERS)
+            return 0;
+        return _handlers[type - 1];
+    }
+
+    SocketInternal* GetInternal(int s)
+    {
+        if (s < 1 || s > MAX_SOCKETS)
+            return 0;
+        return &_sockets[s - 1].si;
+    }
+
+    int RegisterSocketHandler(int type, SocketHandler* handler)
+    {
+       if (type < 1 || type > MAX_SOCKET_HANDLERS)
+            return ERR_SOCKET_TYPE_NOT_FOUND;
+        _handlers[type - 1] = handler;
+        return 0;
+    }
+
+    int Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+    {
+        SocketHandler* h = GetHandler(type);
+        if (!h)
+            return ERR_SOCKET_TYPE_NOT_FOUND;
+        
+        for (int i = 0; i < MAX_SOCKETS; i++)
+        {
+            SocketInternal* si = (SocketInternal*)(_sockets+i);
+            if (si->ID == 0)
+            {
+                si->ID = i+1;
+                si->Type = type;
+                si->Callback = callback;
+                si->userData = userData;
+                printf("Opening socket %d for type %d, invoking 'Open' on %p (=%s)\n", si->ID, type, h, h->Name());
+                return h->Open(si,addr);
+            }
+        }
+        return ERR_SOCKET_NONE_LEFT;
+    }
+
+    int Send(int socket, const u8* data, int len)
+    {
+        SocketInternal* si = GetInternal(socket);
+        if (!si || si->ID != socket)
+            return ERR_SOCKET_NOT_FOUND;
+           // printf("sending %d bytes to socket %d (ID=%d)\n", len, socket, si->ID);
+        return GetHandler(si->Type)->Send(si,data,len);
+    }
+
+    int Close(int socket)
+    {
+        SocketInternal* si = GetInternal(socket);
+        if (!si || si->ID != socket)
+            return ERR_SOCKET_NOT_FOUND;
+        si->SetState(SocketState_Closing);
+        int retval = GetHandler(si->Type)->Close(si);
+        //si->SetState(Socket_Closed);
+        //si->ID = 0;
+        return retval;
+    }
+};
+
+SocketManager gSocketManager;
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+{
+    return gSocketManager.Open(type,addr,callback,userData);
+}
+
+int Socket_Send(int socket, const u8* data, int len)
+{
+    return gSocketManager.Send(socket,data,len);
+}
+
+int Socket_Close(int socket)
+{
+    return gSocketManager.Close(socket);
+}
+
+int RegisterSocketHandler(int type, SocketHandler* handler)
+{
+    return gSocketManager.RegisterSocketHandler(type,handler);
+}
+
+SocketInternal* GetSocketInternal(int socket)
+{
+    return gSocketManager.GetInternal(socket);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.h	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,108 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef SOCKET_H_INCLUDED
+#define SOCKET_H_INCLUDED
+
+#define SOCKET_HCI      1
+#define SOCKET_L2CAP    2
+#define SOCKET_RFCOM    3
+#define SOCKET_SDP      4
+
+typedef struct
+{
+    u8  AddressSpecific[0]; // BDADDR,psm etc
+} SocketAddrHdr;
+
+enum SocketState
+{
+    SocketState_Unknown,
+    SocketState_Opening,
+    SocketState_Open,
+    SocketState_Closing,
+    SocketState_Closed,
+    SocketState_L2CAP_WaitConnect,
+    SocketState_L2CAP_WaitConnectRsp,
+    SocketState_L2CAP_WaitDisconnect,
+    SocketState_L2CAP_Config_wait = 16,
+    SocketState_L2CAP_Config_wait_send,
+    SocketState_L2CAP_Config_wait_req,
+    SocketState_L2CAP_Config_wait_rsp,
+    SocketState_L2CAP_Config_wait_reqrsp  
+};
+
+typedef void (*SocketCallback)(int socket, SocketState state, const u8* data, int len, void* userData);
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData);   // Open a socket
+int Socket_Send(int socket, const u8* data, int len);
+int Socket_State(int socket);
+int Socket_Close(int socket);
+
+//===========================================================================
+//===========================================================================
+//  Don't need to look at or use anything below this line:
+//  Internal representation of socket
+
+class SocketHandler;
+class SocketInternal
+{
+    public:
+
+    u8 ID;
+    u8 State;
+    u8 Type;
+    u8 B0;
+    SocketCallback Callback;
+    void* userData;
+    u8  Data[0];    // Extra socket data starts here
+
+    void Recv(const u8* data, int len)
+    {
+        Callback(ID,(SocketState)State,data,len,userData);
+    }
+
+    void SetState(SocketState state)
+    {
+        State = state;
+        Callback(ID,(SocketState)State,0,0,userData);
+        if (state == SocketState_Closed)
+          ID = 0;
+    }
+};
+
+class SocketHandler
+{
+    public:
+    virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) = 0;
+    virtual int Send(SocketInternal* sock, const u8* data, int len) = 0;
+    virtual int Close(SocketInternal* sock) = 0;
+    virtual char* Name() { return "Base SocketHandler";}
+};
+
+int RegisterSocketHandler(int type, SocketHandler* handler);
+SocketInternal* GetSocketInternal(int socket);
+
+#define ERR_SOCKET_TYPE_NOT_FOUND -200
+#define ERR_SOCKET_NOT_FOUND -201
+#define ERR_SOCKET_NONE_LEFT -202
+
+#endif // SOCKET_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.cpp	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,48 @@
+
+
+#include "mbed.h"
+#include "Utils.h"
+
+void printfBytes(const char* s, const u8* data, int len)
+{
+    printf("%s %d:",s,len);
+    if (len > 256)
+        len = 256;
+    while (len-- > 0)
+        printf(" %02X",*data++);
+    printf("\n");
+}
+
+void printHexLine(const u8* d, int addr, int len)
+{
+    printf("%04X ",addr);
+    int i;
+    for (i = 0; i < len; i++)
+        printf("%02X ",d[i]);
+    for (;i < 16; i++)
+        printf("   ");
+    char s[16+1];
+    memset(s,0,sizeof(s));
+    for (i = 0; i < len; i++)
+    {
+        int c = d[i];
+        if (c < 0x20 || c > 0x7E)
+            c = '.';
+        s[i] = c;
+    }
+    printf("%s\n",s);
+}
+
+void printHex(const u8* d, int len)
+{
+    int addr = 0;
+    while (len)
+    {
+        int count = len;
+        if (count > 16)
+            count = 16;
+        printHexLine(d+addr,addr,count);
+        addr += 16;
+        len -= count;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.h	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,37 @@
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+void DelayMS(int ms);
+
+void printfBytes(const char* label,const u8* data, int len);
+void printHex(const u8* d, int len);
+
+#ifndef min
+#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+inline int LE16(const u8* d)
+{
+    return d[0] | (d[1] << 8);
+}
+
+inline u32 BE32(const u8* d)
+{
+    return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+inline void BE32(u32 n, u8* d)
+{
+    d[0] = (u8)(n >> 24);
+    d[1] = (u8)(n >> 16);
+    d[2] = (u8)(n >> 8);
+    d[3] = (u8)n;
+}
+
+inline void BE16(u32 n, u8* d)
+{
+    d[0] = (u8)(n >> 8);
+    d[1] = (u8)n;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.cpp	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,421 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+#include "hci_private.h"
+#include "USBHost.h" //for USBLoop
+
+enum hci_callback_evt {
+    NONE,
+    CONNECT,
+    DISCONECT,
+    INQUIRYRESULT
+};
+
+#define MAX_BLUETOOTH_ADAPTERS 1
+
+enum StateMask {
+    MASK_RESET = 1,
+    MASK_READ_BUFFER_SIZE = 2,
+    MASK_READ_BD_ADDR = 4,
+    MASK_INITED = 8,
+    MASK_INQUIRY = 16,
+    MASK_REMOTE_NAME = 32,
+    MASK_CREATE_CONNECTION = 64
+};
+
+int  HCI::Open(HCITransport* transport, HCICallback callback) {
+    _transport = transport;
+    _transport->Set(this);
+    _callback = callback;
+    _state = 0;
+    for (int i = 0; i < MAX_BTDEVICES; i++) {
+        _devices[i].Init();
+        _devices[i]._transport = transport;
+    }
+    cmd_credits = 1;
+    return SendCmd(HCI_OP_RESET);
+}
+
+void printf(const BD_ADDR* addr);
+
+BTDevice* HCI::Find(const BD_ADDR* addr) {
+    for (int i = 0; i < MAX_BTDEVICES; i++)
+        if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0)
+            return &_devices[i];
+    return 0;
+}
+
+BTDevice* HCI::Find(int handle) {
+    for (int i = 0; i < MAX_BTDEVICES; i++)
+        if (_devices[i]._state != 0 && handle == _devices[i]._handle)
+            return &_devices[i];
+    return 0;
+}
+//
+bool HCI::Busy() {
+    return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0;
+}
+
+int HCI::Inquiry(int duration) {
+    _state |= MASK_INQUIRY;
+    u8 buf[5];
+    buf[0] = 0x33;//LAP=0x9e8b33
+    buf[1] = 0x8B;
+    buf[2] = 0x9E;
+    buf[3] = duration;
+    buf[4] = 5;  // 5 results
+    SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf));
+    return 0;
+}
+
+int HCI::SendCmd(int cmd, const u8* params, int len) {
+    u8 b[32];
+    b[0] = cmd;
+    b[1] = (cmd >> 8);
+    b[2] = len;
+    if (params)
+        memcpy(b+3,params,len);
+    //printf("%d cmd_credits\n", cmd_credits);
+    while (cmd_credits == 0) {
+        USBLoop();
+        putc('_', stdout);
+    }
+    _transport->HCISend(b,len+3);
+    return 0;
+}
+
+void HCI::OnCommandComplete(int cmd, const u8* data, int len) {
+    printf("%04X %s",cmd,CmdStr(cmd));
+    if (len < 0)
+        return;
+    printfBytes(" complete",data,min(16,len));
+
+    switch (cmd) {
+            //  Init phase 0
+        case HCI_OP_RESET:  // Reset done, init chain to HCI_OP_READ_LOCAL_NAME
+            SendCmd(HCI_OP_READ_BUFFER_SIZE);
+            _state |= MASK_RESET;
+            break;
+
+            //  Init phase 1
+        case HCI_OP_READ_BUFFER_SIZE:
+            _acl_mtu = LE16(data);
+            _sco_mtu = data[2];
+            _acl_max_pkt = LE16(data+3);
+            _sco_max_pkt = LE16(data+5);
+            printf("acl_mtu=%d, acl_max_pkt=%d\n", _acl_mtu, _acl_max_pkt);
+            SendCmd(HCI_OP_READ_BD_ADDR);
+            _state |= MASK_READ_BUFFER_SIZE;
+            break;
+
+            //  Init phase 2
+        case HCI_OP_READ_BD_ADDR:
+            _localAddr = *((BD_ADDR*)data); // Local Address
+            _state |= MASK_READ_BD_ADDR;
+            _state |= MASK_INITED;
+            Callback(CALLBACK_READY,data,6);
+            break;
+
+            // 0CXX
+        case HCI_OP_READ_LOCAL_NAME:
+        case HCI_OP_LINK_KEY_NEG_REPLY:
+            break;
+
+        case HCI_OP_READ_LOCAL_VERSION:
+            // params
+            //SendCmd(HCI_OP_READ_LOCAL_NAME);
+            break;
+
+        case HCI_OP_READ_LOCAL_COMMANDS:
+            break;
+
+        case HCI_OP_READ_LOCAL_FEATURES:
+            //SendCmd(HCI_OP_READ_LOCAL_VERSION);
+            break;
+
+        case HCI_OP_READ_LOCAL_EXT_FEATURES:
+            break;
+
+        case HCI_OP_PIN_CODE_REPLY:
+            printf("Got pin reply\n");
+            break;
+
+        default:
+            printf("Unrecognized Command %04X\n",cmd);
+            break;
+    }
+}
+
+void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) {
+    if (_callback) _callback(this,c,data,len);
+//    (this->*_callback)(c, data, len);
+}
+
+int HCI::RemoteNameRequest(const BD_ADDR* addr) {
+    _state |= MASK_REMOTE_NAME;
+    u8 buf[6+4];
+    memset(buf,0,sizeof(buf));
+    memcpy(buf,addr,6);
+    //buf[7] = 1;
+    return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
+}
+int HCI::RemoteNameRequest(inquiry_info *ii) {
+    _state |= MASK_REMOTE_NAME;
+    u8 buf[6+4];
+    //memset(buf,0,sizeof(buf));
+    memcpy(buf,&ii->bdaddr,6);
+    buf[6] = ii->pscan_rep_mode;
+    buf[7] = 0;
+    *(unsigned short*)(buf+8) = 0;
+    return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
+}
+
+
+int HCI::CreateConnection(const BD_ADDR* remoteAddr) {
+    _state |= MASK_CREATE_CONNECTION;
+    u8 buf[6+7];
+    memset(buf,0,sizeof(buf));
+    memcpy(buf,remoteAddr,6);
+    buf[6] = 0x18;  // DM1,DH1
+    buf[7] = 0xCC;  // DM3, DH3, DM5, DH5
+    buf[8] = 1;     // Page Repetition R1
+    return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf));
+}
+
+int HCI::Disconnect(const BD_ADDR* bdaddr) {
+    BTDevice* d = Find(bdaddr);
+    if (!d)
+        return ERR_HCI_DEVICE_NOT_FOUND;
+    int handle = d->_handle;
+    printf("Disconnect from %d\n",handle);
+    _state |= MASK_CREATE_CONNECTION;
+    u8 buf[3];
+    buf[0] = handle;
+    buf[1] = (handle >> 8);
+    buf[2] = 0x13;
+    return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf));
+}
+
+void HCI::DisconnectComplete(int handle) {
+    BTDevice* d = Find(handle);
+    if (!d)
+        return;
+    d->_handle = 0;
+}
+
+int HCI::DisconnectAll() {
+    BTDevice* devs[8];
+    int count = GetDevices(devs,8);
+    for (int i = 0; i < count; i++)
+        Disconnect(&devs[i]->_info.bdaddr);
+    return 0;
+}
+
+int HCI::PinCodeReply(const u8* data, const u8* pin) {
+    u8 b[6+1+16];
+    memset(b,0,sizeof(b));
+    memcpy(b,data,6);
+    b[6] = 4;
+    memcpy(b+7, pin, 4);
+    return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b));
+}
+
+void HCI::InquiryResult(const inquiry_info* info) {
+    BTDevice* bt = Find(&info->bdaddr);
+    if (!bt) {  // new device
+        for (int i = 0; i < MAX_BTDEVICES; i++) {
+            if (_devices[i]._state == 0) {
+                bt = _devices + i;
+                bt->_state = 1;
+                break;
+            }
+        }
+        if (!bt) {
+            printf("HCI::InquiryResult too many devices\n");
+            return; // Too many devices!
+        }
+    }
+
+    bt->_info = *info;
+}
+
+int HCI::GetDevices(BTDevice** devices, int maxDevices) {
+    int j = 0;
+    for (int i = 0; i < MAX_BTDEVICES; i++) {
+        if (_devices[i]._state != 0) {
+            devices[j++] = _devices + i;
+            if (j == maxDevices)
+                break;
+        }
+    }
+    return j;
+}
+
+void HCI::RemoteName(const BD_ADDR* addr, const char* name) {
+    BTDevice* d = Find(addr);
+    if (d) {
+        strncpy(d->_name,name,sizeof(d->_name)-1);
+        d->_name[sizeof(d->_name)-1] = 0;
+    }
+}
+
+void HCI::ConnectComplete(const connection_info* info) {
+    BTDevice* d = Find(&info->bdaddr);
+    if (!d)
+        return;
+    if (info->status == 0) {
+        d->_handle = info->handle;
+        printf("Connected on %04X\n",info->handle);
+    } else
+        printf("Connection failed with %d\n",info->status);
+}
+
+void HCI::HCIRecv(const u8* data, int len) {
+    // printfBytes(EvtStr(data[0]),data,min(len,16));
+    switch (data[0]) {
+        case HCI_EV_INQUIRY_COMPLETE:
+            printfBytes("Inquiry Complete",data,data[1]);
+            _state &= ~MASK_INQUIRY;
+            Callback(CALLBACK_INQUIRY_DONE,0,0);
+            break;
+
+        case HCI_EV_INQUIRY_RESULT: {
+            const u8* end = data[1] + data + 2;
+            data += 3;
+            while (data < end) {
+                inquiry_info align;
+                memcpy(&align,data,sizeof(inquiry_info));
+                InquiryResult(&align);
+                Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info));
+                data += 14;
+            }
+        }
+        break;
+
+        case HCI_EV_CONN_COMPLETE:
+            _state &= ~MASK_CREATE_CONNECTION;
+            {
+                connection_info align;
+                memcpy(&align,data+2,sizeof(connection_info));
+                ConnectComplete(&align);
+                Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info));
+            }
+            break;
+
+        case HCI_EV_CONN_REQUEST:
+            break;
+
+        case HCI_EV_DISCONN_COMPLETE:
+            DisconnectComplete(LE16(data+3));
+            break;
+
+        case HCI_EV_REMOTE_NAME: {
+            BD_ADDR* addr = (BD_ADDR*)(data+3);
+            const char* name = (const char*)(data + 9);
+            RemoteName(addr,name);
+        }
+        Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1));    // addr is in here too
+        _state &= ~MASK_REMOTE_NAME;
+        break;
+
+        case HCI_EV_CMD_STATUS: {
+            const char* errs = HCIErrStr(data[2]);
+            printf("Status %s %s %d cmd pkts\n",CmdStr(LE16(data+4)),errs, data[3]);
+            cmd_credits = data[3];
+        }
+        Callback(CALLBACK_CMD_STATUS, data+2, 4);
+        break;
+
+        case HCI_EV_CMD_COMPLETE:
+            OnCommandComplete(data[3] | (data[4] << 8),data+6,data[1]-4);
+            cmd_credits = data[2];
+            break;
+
+        case HCI_EV_PIN_CODE_REQ:
+            Callback(CALLBACK_PIN_REQ, data+2, 6);
+            //PinCodeReply(data+2);
+            break;
+
+        case HCI_EV_LINK_KEY_REQ:
+            SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6);
+            break;
+        case HCI_EV_NUM_COMP_PKTS:
+        case HCI_EV_LINK_KEY_NOTIFY:
+            break;
+        default:
+
+            printfBytes("HCIRecv:",data,data[1]+2);
+            break;
+    }
+}
+
+int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+    L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+    L2CAPAddr* l2capaddr = (L2CAPAddr*)addr;
+    BTDevice* bt = Find(&l2capaddr->bdaddr);
+    if (!bt) {
+        printf("Can't open l2cap %d on ",l2capaddr->psm);
+        printf(&l2capaddr->bdaddr);
+        printf("\n");
+        return ERR_HCI_DEVICE_NOT_FOUND;
+    }
+    l2capsock->btdevice = bt;
+    return bt->Open(sock,addr);
+}
+
+int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device
+//assume acl packet
+#if OFFSET==8 //sizeof ACL/L2CAP is include in data/len
+    if (len > _acl_max_pkt)
+#else //OFFSET==0, data is bare application frame
+    if (len+8 > _acl_mtu)
+#endif
+    { printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len);
+    }
+    L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+    return l2capsock->btdevice->Send(sock,data,len);    // Pointless double dispatch
+}
+
+int HCI::Close(SocketInternal* sock) {
+    L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+    return l2capsock->btdevice->Close(sock);    // Pointless double dispatch
+}
+
+void HCI::ACLRecv(const u8* data, int len) {
+    int handle = LE16(data);
+    BTDevice* d = Find(handle & 0x0FFF);
+    if (d)
+        d->ACLRecv(data,len);
+    else
+        printfBytes("HCI:ACLRecv ", data, len);
+}
+
+//===================================================================
+//===================================================================
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.h	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,253 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef HCI_H_INCLUDED
+#define HCI_H_INCLUDED
+
+#include "mbed.h"
+#include "Socket.h"
+
+#pragma pack(1)
+
+#define ERR_HCI_DEVICE_NOT_FOUND -300
+
+class HCI;
+class HCITransport;
+class BTDevice;
+
+typedef struct
+{
+    u8  addr[6];
+} BD_ADDR;
+
+typedef struct
+{
+    BD_ADDR bdaddr;
+    u8  pscan_rep_mode;
+    u8  pscan_period_mode;
+    u8  pscan_mode;
+    u8  dev_class[3];
+    u16 clock_offset;
+} inquiry_info;
+
+typedef struct
+{
+    u8  status;
+    u16 handle;
+    BD_ADDR bdaddr;
+    u8  link_type;
+    u8  encr_mode;
+} connection_info;
+
+//  Address struct for creating L2CAP sockets
+typedef struct {
+    SocketAddrHdr hdr;
+    BD_ADDR bdaddr;
+    u16 psm;
+} L2CAPAddr;
+
+typedef struct {
+    u16    handle;
+    u16    length;            // total
+    u16    l2capLength;    // length -4
+    u16    cid;            // Signaling packet CID = 1
+
+    // Payload
+    u8    cmd;            //
+    u8    id;
+    u16    cmdLength;        // total-8
+    u16 params[4];      // Params
+} L2CAPCmd;
+
+#pragma pack(4)
+
+class BTDevice;
+typedef struct
+{
+    public:
+    SocketInternal si;
+    BTDevice* btdevice;
+    u16 scid;
+    u16 dcid;
+} L2CAPSocket;
+
+#define MAX_HCL_NAME_LENGTH 20  // TODO - BTDevice wants to be a multiple of 4
+
+//  BTDevice encapsulates individual device state
+//  It provides L2CAP layer sockets
+
+class BTDevice : public SocketHandler
+{
+    public:
+    HCITransport* _transport;
+    inquiry_info  _info;
+    u16 _handle;     // acl connection handle
+    u8  _state;      // connection state
+    u8  _txid;
+    u16 peer_mtu;
+    char   _name[MAX_HCL_NAME_LENGTH];
+
+    void Init();
+
+    BD_ADDR* GetAddress() { return &_info.bdaddr; }
+
+    //  Called from HCI
+    void ACLRecv(const u8* data, int len);
+    void ACLFwd(const u8* data, int len);
+
+    // SocketHandler
+    virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+    virtual int Send(SocketInternal* sock, const u8* data, int len);
+    virtual int Close(SocketInternal* sock);
+    virtual char* Name() { return "BTDevice SocketHandler";}
+
+private:
+    int l2cap_sock, plen, contPos, contState;
+    unsigned char *contBuf;
+    Timeout rtx;
+    L2CAPCmd last_req;
+    void repeat_cmd();
+    
+    L2CAPSocket* SCIDToSocket(int scid);
+    int Send(const u8* data, int len);
+    int Send(u8 c, u8 id, u16* params, int count);
+    int Connect(int scid, int psm);
+    int Disconnect(int scid, int dcid);
+    int ConfigureRequest(int dcid);
+    int ConfigureResponse(u8 rxid, int dcid);
+    int DisconnectResponse(u8 rxid, int scid, int dcid);
+    void Control(const u8* data, int len);
+};
+
+enum HCI_CALLBACK_EVENT
+{
+    CALLBACK_NONE,
+    CALLBACK_READY,
+    CALLBACK_INQUIRY_RESULT,
+    CALLBACK_INQUIRY_DONE,
+    CALLBACK_REMOTE_NAME,
+    CALLBACK_CONNECTION_COMPLETE,
+    CALLBACK_CONNECTION_FAILED,
+    CALLBACK_PIN_REQ,
+    CALLBACK_CMD_STATUS
+};
+
+//  L2CAP Protocol/Service Multiplexor (PSM) values
+
+#define L2CAP_PSM_ANY                   0x0000  /* Any/Invalid PSM */
+#define L2CAP_PSM_SDP                   0x0001  /* Service Discovery Protocol */
+#define L2CAP_PSM_RFCOMM                0x0003  /* RFCOMM protocol */
+#define L2CAP_PSM_TCP                   0x0005  /* Telephony Control Protocol */
+#define L2CAP_PSM_TCS                   0x0007  /* TCS cordless */
+#define L2CAP_PSM_BNEP                  0x000f  /* Bluetooth Network Encapsulation Protocol*/
+#define L2CAP_PSM_HID_CNTL              0x0011  /* HID Control */
+#define L2CAP_PSM_HID_INTR              0x0013  /* HID Interrupt */
+#define L2CAP_PSM_ESDP                  0x0015  /* Extended Service Discovery Profile */
+#define L2CAP_PSM_AVCTP                 0x0017  /* Audio/Visual Control Transport Protocol */
+#define L2CAP_PSM_AVDTP                 0x0019  /* Audio/Visual Distribution */
+
+//  Callback from inquiry
+typedef int (*HCICallback)(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len);
+//typedef int (HCI::*HCICallback)(HCI_CALLBACK_EVENT evt, const u8* data, int len);
+
+#define MAX_BTDEVICES 8
+
+class HCITransport;
+class HCI : public SocketHandler
+{
+    HCITransport* _transport;
+    HCICallback _callback;
+    BD_ADDR  _localAddr;
+
+    BTDevice _devices[MAX_BTDEVICES];
+    int _deviceCount;
+
+    int _acl_mtu;
+    int _acl_max_pkt;
+    int _sco_mtu;
+    int _sco_max_pkt;
+
+    int _state;
+char cmd_credits, data_credits;
+    public:
+
+    //  Open a local adapter
+    int Open(HCITransport* transport, HCICallback callback=0);
+
+    //  Return list of discovered addreses
+    int GetDevices(BTDevice** devices, int maxDevices);
+
+    //  Lookup a device by address or handle
+    BTDevice* Find(const BD_ADDR* addr);
+    BTDevice* Find(int handle);
+
+    //  Disconnect from a remote device
+    int Disconnect(const BD_ADDR* addr);
+    int DisconnectAll();
+
+    //  see what devies are in the system
+    int Inquiry(int duration = 10);
+
+    //  get a name, delivered in callback
+    int RemoteNameRequest(const BD_ADDR* addr);
+    int RemoteNameRequest(inquiry_info* ii);
+
+    //  Connect to a remote device
+    int CreateConnection(const BD_ADDR* remoteAddr);
+
+    bool Busy();
+
+    //  called from transport
+    void HCIRecv(const u8* data, int len);
+
+    //  called from transport
+    void ACLRecv(const u8* data, int len);
+
+    //  SocketHandler methods for maintaining L2CAP sockets
+    virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+    virtual int Send(SocketInternal* sock, const u8* data, int len);
+    virtual int Close(SocketInternal* sock);
+    virtual char* Name() { return "HCI SocketHandler";}
+
+private:
+    void    InquiryResult(const inquiry_info* info);
+    void    RemoteName(const BD_ADDR* addr, const char* name);
+    void    ConnectComplete(const connection_info* info);
+    void    DisconnectComplete(int handle);
+    int     SendCmd(int cmd, const u8* params = 0, int len = 0);
+    void    OnCommandComplete(int cmd, const u8* data, int len);
+    virtual void    Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
+protected:
+    int     PinCodeReply(const u8* data, const u8* pin = "0000");
+};
+
+class HCITransport
+{
+protected:
+    HCI* _target;
+public:
+    void Set(HCI* target) { _target = target; };
+    virtual void HCISend(const u8* data, int len) = 0;
+    virtual void ACLSend(const u8* data, int len) = 0;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hci_private.h	Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,323 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef HCI_PRIVATE_H_INCLUDED
+#define HCI_PRIVATE_H_INCLUDED
+
+#define HCI_OP_INQUIRY                0x0401
+#define HCI_OP_INQUIRY_CANCEL        0x0402
+#define HCI_OP_EXIT_PERIODIC_INQ    0x0404
+#define HCI_OP_CREATE_CONN            0x0405
+#define HCI_OP_DISCONNECT            0x0406
+#define HCI_OP_ADD_SCO                0x0407
+#define HCI_OP_CREATE_CONN_CANCEL    0x0408
+#define HCI_OP_ACCEPT_CONN_REQ        0x0409
+#define HCI_OP_REJECT_CONN_REQ        0x040a
+#define HCI_OP_LINK_KEY_REPLY        0x040b
+#define HCI_OP_LINK_KEY_NEG_REPLY    0x040c
+#define HCI_OP_PIN_CODE_REPLY        0x040d
+#define HCI_OP_PIN_CODE_NEG_REPLY    0x040e
+#define HCI_OP_CHANGE_CONN_PTYPE    0x040f
+#define HCI_OP_AUTH_REQUESTED        0x0411
+#define HCI_OP_SET_CONN_ENCRYPT        0x0413
+#define HCI_OP_CHANGE_CONN_LINK_KEY    0x0415
+#define HCI_OP_REMOTE_NAME_REQ        0x0419
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL    0x041a
+#define HCI_OP_READ_REMOTE_FEATURES    0x041b
+#define HCI_OP_READ_REMOTE_EXT_FEATURES    0x041c
+#define HCI_OP_READ_REMOTE_VERSION    0x041d
+#define HCI_OP_SETUP_SYNC_CONN        0x0428
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ    0x0429
+#define HCI_OP_REJECT_SYNC_CONN_REQ    0x042a
+
+#define HCI_OP_SNIFF_MODE            0x0803
+#define HCI_OP_EXIT_SNIFF_MODE        0x0804
+#define HCI_OP_ROLE_DISCOVERY        0x0809
+#define HCI_OP_SWITCH_ROLE            0x080b
+#define HCI_OP_READ_LINK_POLICY        0x080c
+#define HCI_OP_WRITE_LINK_POLICY    0x080d
+#define HCI_OP_READ_DEF_LINK_POLICY    0x080e
+#define HCI_OP_WRITE_DEF_LINK_POLICY    0x080f
+#define HCI_OP_SNIFF_SUBRATE        0x0811
+
+
+#define HCI_OP_SET_EVENT_MASK        0x0c01
+#define HCI_OP_RESET                0x0c03
+#define HCI_OP_SET_EVENT_FLT        0x0c05
+#define HCI_OP_WRITE_LOCAL_NAME        0x0c13
+#define HCI_OP_READ_LOCAL_NAME        0x0c14
+#define HCI_OP_WRITE_CA_TIMEOUT        0x0c16
+#define HCI_OP_WRITE_PG_TIMEOUT        0x0c18
+#define HCI_OP_WRITE_SCAN_ENABLE     0x0c1a
+#define HCI_OP_READ_AUTH_ENABLE        0x0c1f
+#define HCI_OP_WRITE_AUTH_ENABLE    0x0c20
+#define HCI_OP_READ_ENCRYPT_MODE    0x0c21
+#define HCI_OP_WRITE_ENCRYPT_MODE    0x0c22
+    #define ENCRYPT_DISABLED    0x00
+    #define ENCRYPT_P2P        0x01
+    #define ENCRYPT_BOTH        0x02
+#define HCI_OP_READ_CLASS_OF_DEV    0x0c23
+#define HCI_OP_WRITE_CLASS_OF_DEV    0x0c24
+#define HCI_OP_READ_VOICE_SETTING    0x0c25
+#define HCI_OP_WRITE_VOICE_SETTING    0x0c26
+#define HCI_OP_HOST_BUFFER_SIZE        0x0c33
+#define HCI_OP_READ_SSP_MODE        0x0c55
+#define HCI_OP_WRITE_SSP_MODE        0x0c56
+
+#define HCI_OP_READ_LOCAL_VERSION    0x1001
+#define HCI_OP_READ_LOCAL_COMMANDS    0x1002
+#define HCI_OP_READ_LOCAL_FEATURES    0x1003
+#define HCI_OP_READ_LOCAL_EXT_FEATURES    0x1004
+#define HCI_OP_READ_BUFFER_SIZE        0x1005
+#define HCI_OP_READ_BD_ADDR            0x1009
+
+//  events
+#define HCI_EV_INQUIRY_COMPLETE        0x01
+#define HCI_EV_INQUIRY_RESULT        0x02
+#define HCI_EV_CONN_COMPLETE        0x03
+#define HCI_EV_CONN_REQUEST            0x04
+#define HCI_EV_DISCONN_COMPLETE        0x05
+#define HCI_EV_AUTH_COMPLETE        0x06
+#define HCI_EV_REMOTE_NAME            0x07
+#define HCI_EV_ENCRYPT_CHANGE        0x08
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE    0x09
+#define HCI_EV_REMOTE_FEATURES        0x0b
+#define HCI_EV_REMOTE_VERSION        0x0c
+#define HCI_EV_QOS_SETUP_COMPLETE    0x0d
+#define HCI_EV_CMD_COMPLETE            0x0e
+#define HCI_EV_CMD_STATUS            0x0f
+#define HCI_EV_ROLE_CHANGE            0x12
+#define HCI_EV_NUM_COMP_PKTS        0x13
+#define HCI_EV_MODE_CHANGE            0x14
+#define HCI_EV_PIN_CODE_REQ            0x16
+#define HCI_EV_LINK_KEY_REQ            0x17
+#define HCI_EV_LINK_KEY_NOTIFY        0x18
+#define HCI_EV_CLOCK_OFFSET            0x1c
+#define HCI_EV_PKT_TYPE_CHANGE        0x1d
+#define HCI_EV_PSCAN_REP_MODE        0x20
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI    0x22
+#define HCI_EV_REMOTE_EXT_FEATURES    0x23
+#define HCI_EV_SYNC_CONN_COMPLETE    0x2c
+#define HCI_EV_SYNC_CONN_CHANGED    0x2d
+#define HCI_EV_SNIFF_SUBRATE        0x2e
+#define HCI_EV_EXTENDED_INQUIRY_RESULT    0x2f
+#define HCI_EV_IO_CAPA_REQUEST        0x31
+#define HCI_EV_SIMPLE_PAIR_COMPLETE    0x36
+#define HCI_EV_REMOTE_HOST_FEATURES    0x3d
+
+/* Possible error codes */
+#define HCI_UNKNOWN_HCI_COMMAND 0x01
+#define HCI_NO_CONNECTION 0x02
+#define HCI_HW_FAILURE 0x03
+#define HCI_PAGE_TIMEOUT 0x04
+#define HCI_AUTHENTICATION_FAILURE 0x05
+#define HCI_KEY_MISSING 0x06
+#define HCI_MEMORY_FULL 0x07
+#define HCI_CONN_TIMEOUT 0x08
+#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09
+#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A
+#define HCI_ACL_CONNECTION_EXISTS 0x0B
+#define HCI_COMMAND_DISSALLOWED 0x0C
+#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
+#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E
+#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F
+#define HCI_HOST_TIMEOUT 0x10
+#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11
+#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12
+#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13
+#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14
+#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15
+#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16
+#define HCI_REPETED_ATTEMPTS 0x17
+#define HCI_PAIRING_NOT_ALLOWED 0x18
+#define HCI_UNKNOWN_LMP_PDU 0x19
+#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A
+#define HCI_SCO_OFFSET_REJECTED 0x1B
+#define HCI_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_SCO_AIR_MODE_REJECTED 0x1D
+#define HCI_INVALID_LMP_PARAMETERS 0x1E
+#define HCI_UNSPECIFIED_ERROR 0x1F
+#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20
+#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23
+#define HCI_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_UNIT_KEY_USED 0x26
+#define HCI_QOS_NOT_SUPPORTED 0x27
+#define HCI_INSTANT_PASSED 0x28
+#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29
+
+const char* EvtStr(int evt)
+{
+    switch (evt)
+    {
+        case HCI_EV_INQUIRY_COMPLETE:    return "HCI_EV_INQUIRY_COMPLETE";
+        case HCI_EV_INQUIRY_RESULT:    return "HCI_EV_INQUIRY_RESULT";
+        case HCI_EV_CONN_COMPLETE:    return "HCI_EV_CONN_COMPLETE";
+        case HCI_EV_CONN_REQUEST:    return "HCI_EV_CONN_REQUEST";
+        case HCI_EV_DISCONN_COMPLETE:    return "HCI_EV_DISCONN_COMPLETE";
+        case HCI_EV_AUTH_COMPLETE:    return "HCI_EV_AUTH_COMPLETE";
+        case HCI_EV_REMOTE_NAME:    return "HCI_EV_REMOTE_NAME";
+        case HCI_EV_ENCRYPT_CHANGE:    return "HCI_EV_ENCRYPT_CHANGE";
+        case HCI_EV_CHANGE_LINK_KEY_COMPLETE    :    return "HCI_EV_CHANGE_LINK_KEY_COMPLETE";
+        case HCI_EV_REMOTE_FEATURES:    return "HCI_EV_REMOTE_FEATURES";
+        case HCI_EV_REMOTE_VERSION:    return "HCI_EV_REMOTE_VERSION";
+        case HCI_EV_QOS_SETUP_COMPLETE    :    return "HCI_EV_QOS_SETUP_COMPLETE";
+        case HCI_EV_CMD_COMPLETE:    return "HCI_EV_CMD_COMPLETE";
+        case HCI_EV_CMD_STATUS:    return "HCI_EV_CMD_STATUS";
+        case HCI_EV_ROLE_CHANGE:    return "HCI_EV_ROLE_CHANGE";
+        case HCI_EV_NUM_COMP_PKTS:    return "HCI_EV_NUM_COMP_PKTS";
+        case HCI_EV_MODE_CHANGE:    return "HCI_EV_MODE_CHANGE";
+        case HCI_EV_PIN_CODE_REQ:    return "HCI_EV_PIN_CODE_REQ";
+        case HCI_EV_LINK_KEY_REQ:    return "HCI_EV_LINK_KEY_REQ";
+        case HCI_EV_LINK_KEY_NOTIFY:    return "HCI_EV_LINK_KEY_NOTIFY";
+        case HCI_EV_CLOCK_OFFSET:    return "HCI_EV_CLOCK_OFFSET";
+        case HCI_EV_PKT_TYPE_CHANGE:    return "HCI_EV_PKT_TYPE_CHANGE";
+        case HCI_EV_PSCAN_REP_MODE:    return "HCI_EV_PSCAN_REP_MODE";
+        case HCI_EV_INQUIRY_RESULT_WITH_RSSI    :    return "HCI_EV_INQUIRY_RESULT_WITH_RSSI";
+        case HCI_EV_REMOTE_EXT_FEATURES:    return "HCI_EV_REMOTE_EXT_FEATURES";
+        case HCI_EV_SYNC_CONN_COMPLETE:    return "HCI_EV_SYNC_CONN_COMPLETE";
+        case HCI_EV_SYNC_CONN_CHANGED:    return "HCI_EV_SYNC_CONN_CHANGED";
+        case HCI_EV_SNIFF_SUBRATE:    return "HCI_EV_SNIFF_SUBRATE";
+        case HCI_EV_EXTENDED_INQUIRY_RESULT:    return "HCI_EV_EXTENDED_INQUIRY_RESULT";
+        case HCI_EV_IO_CAPA_REQUEST:    return "HCI_EV_IO_CAPA_REQUEST";
+        case HCI_EV_SIMPLE_PAIR_COMPLETE:    return "HCI_EV_SIMPLE_PAIR_COMPLETE";
+        case HCI_EV_REMOTE_HOST_FEATURES:    return "HCI_EV_REMOTE_HOST_FEATURES";
+    }
+    return "Unknown Event";
+}
+
+const char* CmdStr(int cmd)
+{
+    switch (cmd)
+    {
+        // 0x04XX
+        case HCI_OP_INQUIRY:    return "HCI_OP_INQUIRY";
+        case HCI_OP_INQUIRY_CANCEL:    return "HCI_OP_INQUIRY_CANCEL";
+        case HCI_OP_EXIT_PERIODIC_INQ:    return "HCI_OP_EXIT_PERIODIC_INQ";
+        case HCI_OP_CREATE_CONN:    return "HCI_OP_CREATE_CONN";
+        case HCI_OP_DISCONNECT:    return "HCI_OP_DISCONNECT";
+        case HCI_OP_ADD_SCO:    return "HCI_OP_ADD_SCO";
+        case HCI_OP_CREATE_CONN_CANCEL:    return "HCI_OP_CREATE_CONN_CANCEL";
+        case HCI_OP_ACCEPT_CONN_REQ:    return "HCI_OP_ACCEPT_CONN_REQ";
+        case HCI_OP_REJECT_CONN_REQ:    return "HCI_OP_REJECT_CONN_REQ";
+        case HCI_OP_LINK_KEY_REPLY:    return "HCI_OP_LINK_KEY_REPLY";
+        case HCI_OP_LINK_KEY_NEG_REPLY:    return "HCI_OP_LINK_KEY_NEG_REPLY";
+        case HCI_OP_PIN_CODE_REPLY:    return "HCI_OP_PIN_CODE_REPLY";
+        case HCI_OP_PIN_CODE_NEG_REPLY:    return "HCI_OP_PIN_CODE_NEG_REPLY";
+        case HCI_OP_CHANGE_CONN_PTYPE:    return "HCI_OP_CHANGE_CONN_PTYPE";
+        case HCI_OP_AUTH_REQUESTED:    return "HCI_OP_AUTH_REQUESTED";
+        case HCI_OP_SET_CONN_ENCRYPT:    return "HCI_OP_SET_CONN_ENCRYPT";
+        case HCI_OP_CHANGE_CONN_LINK_KEY:    return "HCI_OP_CHANGE_CONN_LINK_KEY";
+        case HCI_OP_REMOTE_NAME_REQ:    return "HCI_OP_REMOTE_NAME_REQ";
+        case HCI_OP_REMOTE_NAME_REQ_CANCEL:    return "HCI_OP_REMOTE_NAME_REQ_CANCEL";
+        case HCI_OP_READ_REMOTE_FEATURES:    return "HCI_OP_READ_REMOTE_FEATURES";
+        case HCI_OP_READ_REMOTE_EXT_FEATURES:    return "HCI_OP_READ_REMOTE_EXT_FEATURES";
+        case HCI_OP_READ_REMOTE_VERSION:    return "HCI_OP_READ_REMOTE_VERSION";
+        case HCI_OP_SETUP_SYNC_CONN:    return "HCI_OP_SETUP_SYNC_CONN";
+        case HCI_OP_ACCEPT_SYNC_CONN_REQ:    return "HCI_OP_ACCEPT_SYNC_CONN_REQ";
+        case HCI_OP_REJECT_SYNC_CONN_REQ:    return "HCI_OP_REJECT_SYNC_CONN_REQ";
+        // 0x0CXX
+        case HCI_OP_SET_EVENT_MASK: return "HCI_OP_SET_EVENT_MASK";
+        case HCI_OP_RESET:            return "HCI_OP_RESET";
+        case HCI_OP_SET_EVENT_FLT:  return "HCI_OP_SET_EVENT_FLT";
+        case HCI_OP_WRITE_LOCAL_NAME:   return "HCI_OP_WRITE_LOCAL_NAME";
+        case HCI_OP_READ_LOCAL_NAME:    return "HCI_OP_READ_LOCAL_NAME";
+        case HCI_OP_WRITE_CA_TIMEOUT:   return "HCI_OP_WRITE_CA_TIMEOUT";
+        case HCI_OP_WRITE_PG_TIMEOUT:   return "HCI_OP_WRITE_PG_TIMEOUT";
+        case HCI_OP_WRITE_SCAN_ENABLE:  return "HCI_OP_WRITE_SCAN_ENABLE";
+        case HCI_OP_READ_AUTH_ENABLE:   return "HCI_OP_READ_AUTH_ENABLE";
+        case HCI_OP_WRITE_AUTH_ENABLE:  return "HCI_OP_WRITE_AUTH_ENABLE";
+        case HCI_OP_READ_ENCRYPT_MODE:  return "HCI_OP_READ_ENCRYPT_MODE";
+        case HCI_OP_WRITE_ENCRYPT_MODE: return "HCI_OP_WRITE_ENCRYPT_MODE";
+        case HCI_OP_READ_CLASS_OF_DEV:  return "HCI_OP_READ_CLASS_OF_DEV";
+        case HCI_OP_WRITE_CLASS_OF_DEV:    return "HCI_OP_WRITE_CLASS_OF_DEV";
+        case HCI_OP_READ_VOICE_SETTING: return "HCI_OP_READ_VOICE_SETTING";
+        case HCI_OP_WRITE_VOICE_SETTING:    return "HCI_OP_WRITE_VOICE_SETTING";
+        case HCI_OP_HOST_BUFFER_SIZE:   return "HCI_OP_HOST_BUFFER_SIZE";
+        case HCI_OP_READ_SSP_MODE:      return "HCI_OP_READ_SSP_MODE";
+        case HCI_OP_WRITE_SSP_MODE: return "HCI_OP_WRITE_SSP_MODE";
+
+        // 10xx
+        case HCI_OP_READ_LOCAL_VERSION: return "HCI_OP_READ_LOCAL_VERSION";
+        case HCI_OP_READ_LOCAL_COMMANDS: return "HCI_OP_READ_LOCAL_COMMANDS";
+        case HCI_OP_READ_LOCAL_FEATURES: return "HCI_OP_READ_LOCAL_FEATURES";
+        case HCI_OP_READ_LOCAL_EXT_FEATURES: return "HCI_OP_READ_LOCAL_EXT_FEATURES";
+        case HCI_OP_READ_BUFFER_SIZE: return "HCI_OP_READ_BUFFER_SIZE";
+        case HCI_OP_READ_BD_ADDR: return "HCI_OP_READ_BD_ADDR";
+    }
+    return "Unknown Cmd";
+}
+
+const char* HCIErrStr(int err)
+{
+    switch (err)
+    {
+        case 0: return "OK";
+        case HCI_UNKNOWN_HCI_COMMAND:    return "HCI_UNKNOWN_HCI_COMMAND";
+        case HCI_NO_CONNECTION:    return "HCI_NO_CONNECTION";
+        case HCI_HW_FAILURE:    return "HCI_HW_FAILURE";
+        case HCI_PAGE_TIMEOUT:    return "HCI_PAGE_TIMEOUT";
+        case HCI_AUTHENTICATION_FAILURE:    return "HCI_AUTHENTICATION_FAILURE";
+        case HCI_KEY_MISSING:    return "HCI_KEY_MISSING";
+        case HCI_MEMORY_FULL:    return "HCI_MEMORY_FULL";
+        case HCI_CONN_TIMEOUT:    return "HCI_CONN_TIMEOUT";
+        case HCI_MAX_NUMBER_OF_CONNECTIONS:    return "HCI_CONN_TIMEOUT";
+        case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE:    return "HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE";
+        case HCI_ACL_CONNECTION_EXISTS:    return "HCI_ACL_CONNECTION_EXISTS";
+        case HCI_COMMAND_DISSALLOWED:    return "HCI_COMMAND_DISSALLOWED";
+        case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES:    return "HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES";
+        case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS:    return "HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS";
+        case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE:    return "HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE";
+        case HCI_HOST_TIMEOUT:    return "HCI_HOST_TIMEOUT";
+        case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE:    return "HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE";
+        case HCI_INVALID_HCI_COMMAND_PARAMETERS:    return "HCI_INVALID_HCI_COMMAND_PARAMETERS";
+        case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED:    return "HCI_OTHER_END_TERMINATED_CONN_USER_ENDED";
+        case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES:    return "HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES";
+        case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF:    return "HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF";
+        case HCI_CONN_TERMINATED_BY_LOCAL_HOST:    return "HCI_CONN_TERMINATED_BY_LOCAL_HOST";
+        case HCI_REPETED_ATTEMPTS:    return "HCI_REPETED_ATTEMPTS";
+        case HCI_PAIRING_NOT_ALLOWED:    return "HCI_PAIRING_NOT_ALLOWED";
+        case HCI_UNKNOWN_LMP_PDU:    return "HCI_UNKNOWN_LMP_PDU";
+        case HCI_UNSUPPORTED_REMOTE_FEATURE:    return "HCI_UNSUPPORTED_REMOTE_FEATURE";
+        case HCI_SCO_OFFSET_REJECTED:    return "HCI_SCO_OFFSET_REJECTED";
+        case HCI_SCO_INTERVAL_REJECTED:    return "HCI_SCO_INTERVAL_REJECTED";
+        case HCI_SCO_AIR_MODE_REJECTED:    return "HCI_SCO_AIR_MODE_REJECTED";
+        case HCI_INVALID_LMP_PARAMETERS:    return "HCI_INVALID_LMP_PARAMETERS";
+        case HCI_UNSPECIFIED_ERROR:    return "HCI_UNSPECIFIED_ERROR";
+        case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE:    return "HCI_UNSUPPORTED_LMP_PARAMETER_VALUE";
+        case HCI_ROLE_CHANGE_NOT_ALLOWED:    return "HCI_ROLE_CHANGE_NOT_ALLOWED";
+        case HCI_LMP_RESPONSE_TIMEOUT:    return "HCI_LMP_RESPONSE_TIMEOUT";
+        case HCI_LMP_ERROR_TRANSACTION_COLLISION:    return "HCI_LMP_ERROR_TRANSACTION_COLLISION";
+        case HCI_LMP_PDU_NOT_ALLOWED:    return "HCI_LMP_PDU_NOT_ALLOWED";
+        case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE:    return "HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE";
+        case HCI_UNIT_KEY_USED:    return "HCI_UNIT_KEY_USED";
+        case HCI_QOS_NOT_SUPPORTED:    return "HCI_QOS_NOT_SUPPORTED";
+        case HCI_INSTANT_PASSED:    return "HCI_INSTANT_PASSED";
+        case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED:    return "HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED";
+    };
+    return "Unknow HCI err";
+};
+
+
+#endif // HCI_PRIVATE_H_INCLUDED