Based on myBlueUSB reference ver. http://mbed.org/users/networker/programs/myBlueUSB/lsm1ui

Dependencies:   mbed myUSBHost AvailableMemory rfcomm myBlueUSB sdp

Files at this revision

API Documentation at this revision

Comitter:
kenbumono
Date:
Tue Jul 05 08:25:59 2011 +0000
Commit message:

Changed in this revision

AutoEvents.cpp Show annotated file Show diff for this revision Revisions of this file
AvailableMemory.lib Show annotated file Show diff for this revision Revisions of this file
FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TestShell.cpp Show annotated file Show diff for this revision Revisions of this file
btserial.cpp Show annotated file Show diff for this revision Revisions of this file
btserial.h Show annotated file Show diff for this revision Revisions of this file
ftclasslibusbdevbt.cpp Show annotated file Show diff for this revision Revisions of this file
ftclasslibusbdevbt.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
motordriver.cpp Show annotated file Show diff for this revision Revisions of this file
motordriver.h Show annotated file Show diff for this revision Revisions of this file
myBlueUSB.lib Show annotated file Show diff for this revision Revisions of this file
myUSBHost.lib Show annotated file Show diff for this revision Revisions of this file
neighbourhood.cpp Show annotated file Show diff for this revision Revisions of this file
neighbourhood.h Show annotated file Show diff for this revision Revisions of this file
rfcomm.lib Show annotated file Show diff for this revision Revisions of this file
sdp.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AutoEvents.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,161 @@
+
+/*
+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 "mbed.h"
+#include "USBHost.h"
+#include "Utils.h"
+
+#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol)
+#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1)
+#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2)
+
+u8 auto_mouse[4];       // buttons,dx,dy,scroll
+u8 auto_keyboard[8];    // modifiers,reserved,keycode1..keycode6
+u8 auto_joystick[4];    // x,y,buttons,throttle
+
+void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
+{
+    int evt = (int)userData;
+    switch (evt)
+    {
+        case AUTO_KEYBOARD:
+            printf("AUTO_KEYBOARD ");
+            break;
+        case AUTO_MOUSE:
+            printf("AUTO_MOUSE ");
+            break;
+        default:
+            printf("HUH ");
+    }
+    printfBytes("data",data,len);
+    USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData);
+}
+
+//  Establish transfers for interrupt events
+void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed)
+{
+    if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80))
+        return;
+    
+    // Make automatic interrupt enpoints for known devices
+    u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol);
+    u8* dst = 0;
+    int len;
+    switch (evt)
+    {
+        case AUTO_MOUSE:
+            dst = auto_mouse;
+            len = sizeof(auto_mouse);
+            break;
+        case AUTO_KEYBOARD:
+            dst = auto_keyboard;
+            len = sizeof(auto_keyboard);
+            break;
+        default:
+            printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt);
+            break;
+    }
+    if (dst)
+    {
+        printf("Auto Event for %02X %08X\n",ed->bEndpointAddress,evt);
+        USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt);
+    }
+}
+
+void PrintString(int device, int i)
+{
+    u8 buffer[256];
+    int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255);
+    if (le < 0)
+         return;
+    char* dst = (char*)buffer;
+    for (int j = 2; j < le; j += 2)
+        *dst++ = buffer[j];
+    *dst = 0;
+    printf("%d:%s\n",i,(const char*)buffer);
+ }
+ 
+//  Walk descriptors and create endpoints for a given device
+int StartAutoEvent(int device, int configuration, int interfaceNumber)
+{
+    u8 buffer[255];
+    int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255);
+    if (err < 0)
+        return err;
+
+    int len = buffer[2] | (buffer[3] << 8);
+    u8* d = buffer;
+    u8* end = d + len;
+    while (d < end)
+    {
+        if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
+        {
+            InterfaceDescriptor* id = (InterfaceDescriptor*)d;
+            if (id->bInterfaceNumber == interfaceNumber)
+            {
+                 d += d[0];
+                while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
+                {
+                    if (d[1] == DESCRIPTOR_TYPE_ENDPOINT)
+                        AddAutoEvent(device,id,(EndpointDescriptor*)d);
+                    d += d[0];
+                }
+            }
+        }
+        d += d[0];
+    }
+    return 0;
+}
+
+//  Implemented in main.cpp
+int OnDiskInsert(int device);
+
+//  Implemented in TestShell.cpp
+int OnBluetoothInsert(int device);
+
+void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc)
+{
+    printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol);
+    char s[128];
+    for (int i = 1; i < 3; i++)
+    {
+        if (GetString(device,i,s,sizeof(s)) < 0)
+            break;
+        printf("%d: %s\n",i,s);
+    }
+    
+    switch (interfaceDesc->bInterfaceClass)
+    {
+        case CLASS_MASS_STORAGE:
+            if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50)
+                OnDiskInsert(device);    // it's SCSI!
+            break;
+        case CLASS_WIRELESS_CONTROLLER:
+            if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01)
+                OnBluetoothInsert(device);    // it's bluetooth!
+            break;
+        default:
+            StartAutoEvent(device,1,0);
+            break;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AvailableMemory.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/networker/code/AvailableMemory/#2b2aa11cebd7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestShell.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,347 @@
+
+/*
+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 "mbed.h"
+#include <vector>
+#include "Utils.h"
+#include "USBHost.h"
+#include "hci.h"
+#include "HCITransportUSB.h"
+#include "RFCOMM.h"
+#include "ftclasslibusbdevbt.h"
+#include "sdp_data.h"
+#include "sdp.h"
+#include "btserial.h"
+#include "neighbourhood.h"
+
+#include "motordriver.h"
+
+/************************************************
+TODO:
+mtu and credits are completely unhandled - in progress
+multiple rfcomm sessions should be possible - done
+SDP would be nice - beta
+multiple rfcomm channels are untested
+decoupling of rfcomm and application - much better
+packets are not reassembled - some are (HCI and ft application level)
+disconnect and timeouts
+************************************************/
+#define DEBUG   1
+int state = 0;
+
+//int bulk = 0;
+void printf(const BD_ADDR* addr) {
+    const u8* a = addr->addr;
+    printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]);
+}
+
+const char FtDevClass[3] = {0x00, 0x1F, 0x82 };
+const char SerDevClass[3] = {4, 1, 0x00};
+//  Instance
+extern RFCOMMManager rfcomm_manager;
+
+class application : public HCI {
+    BTDevice* devs[8];
+    int count, i, pending;
+public:
+    //  We have connected to a device
+    void ConnectionComplete(connection_info* info) {
+        printf("ConnectionComplete ");
+        BD_ADDR* a = &info->bdaddr;
+        printf(a);
+        printf("\n");
+        RemoteNameRequest(a);
+        for (i++; i < count; i++) {//find the next device to open
+            printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
+            if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices
+                BD_ADDR* bd = &devs[i]->_info.bdaddr;
+                printf("Connecting to ");
+                printf(bd);
+                printf("\n");
+                pending++;
+                CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
+                printf("connection cmd was sent\n");
+                return;
+            }
+        }
+        //state = 1; //start the real application
+    }
+
+    void ConnectDevices() {
+        count = GetDevices(devs,8);//get pointers to all bluetooth devices
+        pending = 0;
+        for (i = 0; i < count; i++) {
+            printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
+            if (devs[i]->_handle == 0 /*&& memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0*/) {//or some other way to connect to RFCOMM devices
+                BD_ADDR* bd = &devs[i]->_info.bdaddr;
+                printf("Connecting to ");
+                printf(bd);
+                printf("\n");
+                pending++;
+                CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
+                printf("connection cmd was sent\n");
+                return;
+            }
+        }
+        if (pending == 0) state = 1;//for the case when there are no ft devices
+    }
+    virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
+    int csr_write_bd_addr(BD_ADDR *bdaddr, bool transient=true);
+    int csr_reset_device(bool transient=true);
+} App; //application instance
+
+extern "C" void mbed_reset();
+
+
+void application::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv
+    unsigned char pin[] = "1234";
+    unsigned char newaddr[] = {0x2c, 0x07, 0x54, 0x7b, 0x13, 0x00};//possible ft TX address (ROBO TX-277)
+//    unsigned char newaddr[] = {0x57, 0x0a, 0x3d, 0x83, 0x15, 0x00};//original address of the cheap round BT dongle
+    printf("\x1b[%dm", 33);
+    switch (evt) {
+        case CALLBACK_READY:
+            printf("CALLBACK_READY\n");
+            printf("my address = ");
+            printf((BD_ADDR*)data);
+            if (memcmp(newaddr, data, 6) != 0) { //csr_write_bd_addr((BD_ADDR*)newaddr, false);
+            }
+            Inquiry();//start the second phase of the discovery
+            break;
+
+        case CALLBACK_INQUIRY_RESULT: //optionally build the list of FT devices here
+            printf("CALLBACK_INQUIRY_RESULT ");
+            printf((BD_ADDR*)data);
+            printf("\n");//data points to inquiry_info struct
+//          RemoteNameRequest((BD_ADDR*)data);
+            break;
+
+        case CALLBACK_INQUIRY_DONE:
+            printf("CALLBACK_INQUIRY_DONE\n");
+            neighbors = new neighbourhood(&App);
+            neighbors->read();
+            ConnectDevices();
+            break;
+
+        case CALLBACK_REMOTE_NAME: {
+            BD_ADDR* addr = (BD_ADDR*)data;
+            const char* name = (const char*)(data + 6);
+            printf(addr);
+            printf(" = % s\n",name);
+            pending--;
+            if (pending == 0) state = 1;
+        }
+        break;
+
+        case CALLBACK_CONNECTION_COMPLETE: {
+            connection_info *ci = (connection_info*)data;
+            if (ci->status>0) {
+                printf("Connection failed, status=0x%02X\n", ci->status);
+                break;
+            }
+            ConnectionComplete(ci);
+            printf("Going to open sdp socket\n");
+            L2CAPAddr addr;
+            memcpy(&addr.bdaddr, &ci->bdaddr, 6);
+            //int s = SDP.Open(&addr.hdr);
+        }
+        break;
+        case CALLBACK_PIN_REQ:
+            printf("Enter PIN for ");
+            printf((BD_ADDR*)data);
+            printf(" :  submitting %s\n", pin);
+            //USBLoop(); wait(1.0); USBLoop();
+            //for(int k=0; k<2000000;k++) USBLoop();
+            PinCodeReply(data, pin);
+            break;
+        case CALLBACK_VENDOR:
+            printfBytes("Vendor Reply:", data, len);
+            //mbed_reset();
+            if (data[0] == 0xc2)
+                csr_reset_device(false);
+            break;
+        default:
+            printf("Unhandled HCI Callback %d\n", evt);
+    };
+    printf("\x1b[%dm", 0);
+}
+
+#define CSR_WRITE        0xFC00
+
+int application::csr_write_bd_addr(BD_ADDR *bdaddr, bool transient) {
+    unsigned char cmd[] = { 0xc2,
+                            0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
+                            0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+                          };
+
+    if (transient)
+        cmd[15] = 0x08;
+
+    cmd[17] = bdaddr->addr[2];
+    cmd[18] = 0x00;
+    cmd[19] = bdaddr->addr[0];
+    cmd[20] = bdaddr->addr[1];
+    cmd[21] = bdaddr->addr[3];
+    cmd[22] = 0x00;
+    cmd[23] = bdaddr->addr[4];
+    cmd[24] = bdaddr->addr[5];
+
+    return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
+}
+
+int application::csr_reset_device(bool transient) {
+    unsigned char cmd[] = { 0xc2, 0x02, 0x00, 0x09, 0x00,
+                            0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+                          };
+
+    if (transient)
+        cmd[7] = 0x02;
+
+    return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
+}
+
+
+//  these should be placed in the DMA SRAM
+typedef struct {
+    u8 _hciBuffer[MAX_HCL_SIZE];
+    u8 _aclBuffer[MAX_ACL_SIZE];
+} SRAMPlacement;
+
+HCITransportUSB _HCITransportUSB;  //use USB as the transport to the radio
+
+int OnBluetoothInsert(int device) {//install the HCI and start discovery, user callbacks are made to HciCalback
+    printf("Bluetooth inserted of %d\n",device);
+    u32 sramLen;
+    u8* sram =  USBGetBuffer(&sramLen);
+    sram = (u8*)(((u32)sram + 1023) & ~1023);
+    SRAMPlacement* s = (SRAMPlacement*)sram;
+    _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer);//setup buffers for USB host, incoming data goes first to HCIRecv and ACLRecv
+    RegisterSocketHandler(SOCKET_L2CAP,&App); //register the application::hci as handler for L2CAP events
+    RegisterSocketHandler(SOCKET_RFCOM, &rfcomm_manager);//set the RFCOMMManager as the RFCOM socket handler
+    if (RegisterSocketHandler(SOCKET_SDP, &SDP))
+        printf("Could not register SDP socket type\n");
+    App.Open(&_HCITransportUSB);//the callback is virtual
+    App.Inquiry();//start discovery of BT devices phase 0
+    return 0;
+}
+
+DigitalOut led(LED1), loop(LED2);
+
+int comm = 0;
+btserial *incoming, *outgoing;
+
+Motor motorRight(p21, p5, p6, 1); // pwm, fwd, rev, can break
+Motor motorLeft(p22, p7, p8, 1); // pwm, fwd, rev, can break
+
+void motorSpeed(Motor& motor, int stick)
+{
+    float speed;
+    if(100 <= stick && stick <= 155) {
+        motor.stop(0);
+    } else if(0 <= stick && stick <= 99) {
+        speed = (100 - stick) * 0.01;
+        motor.speed(speed);
+        printf("Motor:%f", speed);
+    } else {
+        speed = (155 - stick) * 0.01;
+        motor.speed(speed);
+        printf("Motor:%f", speed);
+    }
+}
+
+void echo(int socket, SocketState state, const u8* data, int len, void* userData) {
+    const u8 connack[] = { 0xbe, 0xef, 8, 'C','O','N','N','_','A','C','K', 0x11};
+    printf("Echo: socket %d, state %d, len=%d\n", socket, state, len);
+    if (state==SocketState_Open) {
+        if (len == 0) {
+            printf("Sending CONN_ACK\n");
+            Socket_Send(socket, connack, sizeof(connack));
+        } else {
+            //Socket_Send(socket, data, len);
+            printfBytes("echo:", data, len);
+            
+            if(len >= 4) {
+                char temp[5] = {0};
+                memcpy(temp, data, 4);
+                int num = strtol(temp, NULL, 16);
+                
+                int LeftStickY = num / 256;
+                int RightStickY = num - (LeftStickY * 256);
+    
+                motorSpeed(motorLeft, LeftStickY);
+                motorSpeed(motorRight, RightStickY);
+            }
+        }
+    }
+}
+
+void TestShell() {
+    int n=0;
+    USBInit();
+    for (;;) {
+        switch (state) {
+            case 0: //inquiry and low-level connection
+                break;
+            case 1: {//initialisation
+                printf("Ready to open ports\n");
+                InitFtBtDeviceList();
+                int n = GetNrOfFtBtDevices();
+                printf("%d ft BT devices have been found\n", n);
+                if (n > 0) {
+                    ftbtdev *d = GetFtUsbDeviceHandle(0);
+                    if (d==0) printf("could not get device handle\n");
+                    //int sock = OpenFtBtDevice(d);
+                }
+                state = 2;
+                comm = Socket_Listen(SOCKET_RFCOM, 1, echo, 0);
+                //incoming = new btserial(1);
+            }
+            break;
+            case 2://main loop
+                /*   if (incoming->readable()>0){
+                     int c= incoming->getc();
+                     putc(c, stderr);
+                     incoming->putc(c);
+                     }
+                     else if (incoming->readable()<0){
+                       state = 3;
+                       printf("end of session");
+                       delete incoming;
+                     }*/
+                break;
+            default:
+                break;
+        }
+        loop=1;
+        USBLoop();
+        loop=0;
+        n++;
+        if (n>=500000) {
+            n=0;
+            led = !led;
+        }
+    }
+    //printf("Dropped out of main loop!\n");
+}
+
+//********************************************************************************************************************************
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btserial.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+#include "btserial.h"

btserial::btserial(char ba[6], char ch) {
    L2CAPAddr a;
    memcpy(&a.bdaddr, ba, 6);
    a.psm = ch;
    sendptr = 0;
    recptrin = 0;
    recptrout = bufsize - 1;
    free = bufsize;
    sock = Socket_Open(SOCKET_RFCOM, &a.hdr,  cb, this);
}

btserial::btserial(char ch) {
    sendptr = 0;
    recptrin = 0;
    recptrout = bufsize - 1;
    free = bufsize;
    sock = Socket_Listen(SOCKET_RFCOM, ch,  cb, this);
}

void btserial::cb(int socket, SocketState state, const unsigned char *data, int len, void* userData) {
    btserial *self = (btserial*)userData;
    if (state == SocketState_Open)
        if (len > 0)
            self->stash(data, len);
        else {
            port_settings ps;//defaults are ok
            ps.baud = 3; //9600 baud
            ps.bits = 3;//8 bits
            ps.stop = 0;//1 bit
            ps.par = 0; //no parity
            ps.mask = MASK_BITRATE|MASK_DATABITS|MASK_STOPBITS|MASK_PARITYBITS;
            //set_remote_port_parameters(sock, &ps);
            self->open = true;
        }
        else if (state == SocketState_Closed)
          self->open = false;
}

void btserial::stash(const unsigned char *data, int len) {
    int i = 0;
    while (i < len && free>0) {
        recbuf[recptrin++] =  data[i++];
        if (recptrin == bufsize) recptrin = 0;
        free--;
    }
}

int btserial::getc() {
    if (free == bufsize || !open)
        return -1;
    free++;
    recptrout++;
    if (recptrout == bufsize) recptrout = 0;
    return recbuf[recptrout];
}

int btserial::putc(int c) {
    if (sendptr==bufsize || !open)
        return -1;
    sendbuf[sendptr++] = c;
    if (sendptr==bufsize || c=='\n' || c=='\r') {
        Socket_Send(sock, sendbuf, sendptr);
        sendptr = 0;
    }
    return c;
}

void btserial::baud(int br) {
    int rates[] = {2400,4800,7200,9600,19200,38400,57600,115200,230400};
    if (!open) return;
    for (int i = 0; i < sizeof(rates)/sizeof(int);i++)
        if (rates[i] == br) {
            port_settings ps;
            ps.baud = i;
            ps.mask = MASK_BITRATE;
            set_remote_port_parameters(sock, &ps);
            return;
        }
    printf("Illegal baudrate requested %d\n", br);
}

void btserial::format(int bits, Serial::Parity par, int stop) {
if (!open) return;
    port_settings ps;
    ps.bits = bits-5;
    ps.stop = stop-1;
    switch (par) {
        case Serial::None:
            ps.par = 0;
            ps.par_t = 0;
            break;
        case Serial::Odd:
            ps.par = 1;
            ps.par_t = 0;
            break;
        case Serial::Even:
            ps.par = 1;
            ps.par_t = 1;
            break;
        case Serial::Forced0:
            ps.par = 1;
            ps.par_t = 3;
            break;
        case Serial::Forced1:
            ps.par = 1;
            ps.par_t = 2;
            break;
    }
    ps.mask = MASK_DATABITS|MASK_STOPBITS|MASK_PARITYBITS|MASK_PARITYTYPE;
    set_remote_port_parameters(sock, &ps);
}

\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btserial.h	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,31 @@
+#ifndef BTSERIAL_H
+#define BTSERIAL_H
+#include "mbed.h"
+#include "RFCOMM.h"
+
+class btserial {
+    static const int bufsize = 127;
+    int sock;
+    unsigned char sendbuf[bufsize], recbuf[bufsize];
+    int sendptr, recptrin, recptrout, free;
+    static void cb(int socket, SocketState state, const unsigned char *data, int len, void* userData);
+    void stash(const unsigned char *data, int len);
+    bool open;
+public:
+    btserial(char ba[6], char ch);//outgoing
+    btserial(char ch);//incoming
+    void baud(int);
+    void format(int, Serial::Parity, int);
+    int putc(int);
+    int getc();
+    int readable() {
+        if (!open) return -1;
+        return bufsize-free;
+    }
+    int writeable() {
+        if (!open) return -1;
+        return bufsize - sendptr;
+    }
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ftclasslibusbdevbt.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,134 @@
+#include "mbed.h"
+#include <vector>
+#include "Utils.h"
+#include "hci.h"
+#include "ftclasslibusbdevbt.h"
+
+//extern HCI* gHCI;
+class application;
+extern application App;
+
+void printf(const BD_ADDR* addr);
+
+void ftdev::receive(int socket, SocketState state, const u8* data, int len) {
+    printf("ftdev::receive was called: socket %d, state=%d, length=%d\n", socket, state, len);
+//    unsigned char req[] = "\xdget_ser_num\xd";
+    unsigned char req[] = {0xbe, 0xef, 6, 0xfc, 0,0,0,0,0, 0xaf};
+    if (len==0) {
+        switch (state) {
+            case SocketState_Opening:
+                break;
+            case SocketState_Open:
+                printf("sending request \n%s\n", req);
+                Socket_Send(sock, req, sizeof(req));
+                break;
+            case SocketState_Closing:
+            case SocketState_Closed:
+                return;
+        }
+    } else {
+        //printHex(data, len);
+        parse(data, len);
+        if (state==SocketState_Open)
+            ;//Socket_Close(sock);//replace with ft primitive
+    }
+}
+
+unsigned short ftdev::chksum() {
+    unsigned short sum = (X1_len & 0xFF) + (X1_len >> 8);
+    for (int i = 0; i < X1_len; i++)
+        sum += X1_pkt[i];
+    return -sum;
+}
+
+void ftdev::parse (const unsigned char *buf, unsigned len) {
+    unsigned i = 0;
+    while (i < len) {
+        char c = buf[i++];
+        switch (parseState) {
+            case 0: //ascii state
+                if (c==2)
+                    parseState = 1;
+                else
+                    putc(c, stdout);
+                break;
+            case 1:
+                if (c==0x55)
+                    parseState = 2;
+                else {
+                    parseState = 0;
+                    printf("expected 0x55 in X1 header, found %02X\n", c);
+                }
+                break;
+            case 2:
+                X1_len = c<<8;
+                parseState= 3;
+                break;
+            case 3:
+                X1_len += c;
+                parseState= 4;
+                X1_pkt = new unsigned char[X1_len];
+                X1_pos = 0;
+                break;
+            case 4:
+                if  (X1_pos < X1_len) X1_pkt[X1_pos++] = c;
+                else parseState = 5;
+                break;
+            case 5:
+                X1_crc = c<<8;
+                parseState= 6;
+                break;
+            case 6:
+                X1_crc += c;
+                parseState= 7;
+                break;
+            case 7:
+                if (c == 3 && X1_crc == chksum()) {
+                   //handlePkt();
+                   printHex(X1_pkt, X1_len);
+                }else
+                    printf("framing or checksum error, end char = %02X\n", c);
+                
+                parseState = 0;
+                break;
+        }
+    }
+}
+
+vector<ftbtdev*> ft_devs;
+ftdev  _ftdev; //single instance, just for test
+
+int GetNrOfFtBtDevices() {
+    return ft_devs.size();
+}
+
+unsigned InitFtBtDeviceList() {//assume inquiry has been done
+    static char FtDevClass[3] = {0x00, 0x1F, 0x82 };
+    BTDevice* devs[8];
+    int count = ((HCI*)&App)->GetDevices(devs,8);
+    int n = 0;
+    for (int i = 0; i < count; i++) {
+        if (memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {
+            ft_devs.push_back(new ftbtdev(&devs[i]->_info));
+            printf("%d: %s\n", n++, devs[i]->_name);
+        }
+//        printf("device %d (handle=%d) ", i, devs[i]->_handle);
+//        printfBytes("devclass: ", devs[i]->_info.dev_class, 3);
+    }
+    return n;
+}
+
+ftbtdev* GetFtUsbDeviceHandle(unsigned  Num) {
+    if (Num < ft_devs.size()) {
+        return ft_devs[Num];
+    }
+    return 0;
+}
+
+unsigned OpenFtBtDevice(ftbtdev* d) {
+    BD_ADDR* bd = d->BtAddr();
+    printf("Connecting to ");
+    printf(bd);
+    printf("\n");
+    return _ftdev.Open(bd, 1); //TODO: everything can go wrong here
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ftclasslibusbdevbt.h	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,47 @@
+#ifndef FTCLASSLIBUSBDEVBT_H
+#define FTCLASSLIBUSBDEVBT_H
+
+
+class ftbtdev {//small object for ft BT enumeration
+    inquiry_info info;
+public:
+    ftbtdev(inquiry_info* ii) {
+        info = *ii;
+    }
+    BD_ADDR* BtAddr() {
+        return &info.bdaddr;
+    }
+};
+
+class ftdev {//this should in the future encapsulate the real TXC
+    int sock;
+    int parseState;
+    unsigned short X1_crc, X1_len, X1_pos;
+    unsigned char *X1_pkt;
+    unsigned short chksum();
+    void parse(const unsigned char *, unsigned);
+public:
+    ftdev(): sock(0) { parseState = 0;}
+    int Open(BD_ADDR *bt_addr, int chan=1, SocketCallback cb=&ftdev::recv) {
+        L2CAPAddr s;
+        s.bdaddr = *bt_addr;
+        s.psm = chan;//abuse the psm for the channelID
+        sock = Socket_Open(SOCKET_RFCOM, &s.hdr, cb, this);//Open the serial connection via RFCOMM
+        if (sock<=0)
+           printf("Opening of RFCOMM socket for ftdevice failed (%d)\n", sock);
+        return sock;
+    }
+    static void recv(int socket, SocketState state, const u8* data, int len, void* userData) {
+        if (userData) ((ftdev*)userData)->receive(socket, state, data, len);
+    }
+    void receive(int socket, SocketState state, const u8* data, int len);// {printf("ftdev::receive was called: socket %d, state=%d, length=%d\n", socket, state, len);}
+};
+
+extern ftdev _ftdev;
+
+unsigned InitFtBtDeviceList();
+int GetNrOfFtBtDevices();
+ftbtdev* GetFtUsbDeviceHandle(unsigned  Num);
+unsigned OpenFtBtDevice(ftbtdev* d);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,121 @@
+/*
+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 "mbed.h"
+#include "USBHost.h"
+#include "Utils.h"
+#include "FATFileSystem.h"
+
+int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
+int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
+int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
+
+class USBFileSystem : public FATFileSystem
+{
+    int _device;
+    u32 _blockSize;
+    u32 _blockCount;
+    
+public:
+    USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0)
+    {
+    }
+    
+    void SetDevice(int device)
+    {
+        _device = device;
+    }
+    
+    virtual int disk_initialize()
+    {
+        return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize);
+    }
+    
+    virtual int disk_write(const char *buffer, int block_number)
+    {
+        return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize);
+    }
+    
+    virtual int disk_read(char *buffer, int block_number)
+    {
+        return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize);
+    }
+        
+    virtual int disk_sectors()
+    {
+        return _blockCount;
+    }
+};
+
+void DumpFS(int depth, int count)
+{
+    DIR *d = opendir("/usb");
+    if (!d)
+    {
+        printf("USB file system borked\n");
+        return;
+    }
+
+    printf("\nDumping root dir\n");
+    struct dirent *p;
+    for(;;)
+    {
+        p = readdir(d);
+        if (!p)
+            break;
+        int len = sizeof( dirent);
+        printf("%s %d\n", p->d_name, len);
+    }
+    closedir(d);
+}
+
+int OnDiskInsert(int device)
+{
+    USBFileSystem fs;
+    fs.SetDevice(device);
+    DumpFS(0,0);
+    return 0;
+}
+
+/*
+    Simple test shell to exercise mouse,keyboard,mass storage and hubs.
+    Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it.
+*/
+
+Serial pc(USBTX, USBRX);
+int GetConsoleChar()
+{
+    if (!pc.readable())
+        return -1;
+    char c = pc.getc();
+    pc.putc(c); // echo
+    return c;
+}
+
+void TestShell();
+
+int main()
+{
+    pc.baud(460800);
+    printf("BlueUSB\nNow get a bunch of usb or bluetooth things and plug them in\n");
+    TestShell();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motordriver.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,142 @@
+/*motor driver libary modified from the following libary,
+*
+* mbed simple H-bridge motor controller
+* Copyright (c) 2007-2010, sford
+*
+* by Christopher Hasler.
+*
+* from sford's libary,
+*
+* 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 "motordriver.h"
+
+#include "mbed.h"
+
+Motor::Motor(PinName pwm, PinName fwd, PinName rev, bool brakeable):
+        _pwm(pwm), _fwd(fwd), _rev(rev), _brakeable(brakeable), _sign(0) {
+
+    // Set initial condition of PWM
+    _pwm.period(0.001);
+    _pwm = 0;
+
+    // Initial condition of output enables
+    _fwd = 0;
+    _rev = 0;
+}
+
+float Motor::speed(float speed) {
+    float temp = 0;
+    if (_sign == 0) {
+        _fwd = (speed > 0.0);
+        _rev = (speed < 0.0);
+        temp = abs(speed);
+        _pwm = temp;
+    } else if (_sign == 1) {
+        if (speed < 0) {
+            _fwd = (speed > 0.0);
+            _rev = (speed < 0.0);
+            _pwm = 0;
+            temp = 0;
+       } else {
+            _fwd = (speed > 0.0);
+            _rev = (speed < 0.0);
+            temp = abs(speed);
+            _pwm = temp;
+        }
+    } else if (_sign == -1) {
+        if (speed > 0) {
+            _fwd = (speed > 0.0);
+            _rev = (speed < 0.0);
+            _pwm = 0;
+            temp = 0;
+        } else {
+            _fwd = (speed > 0.0);
+            _rev = (speed < 0.0);
+            temp = abs(speed);
+            _pwm = temp;
+        }
+    }
+    if (speed > 0)
+        _sign = 1;
+    else if (speed < 0) {
+        _sign = -1;
+    } else if (speed == 0) {
+        _sign = 0;
+    }
+    return temp;
+}
+//  (additions)
+void Motor::coast(void) {
+    _fwd = 0;
+    _rev = 0;
+    _pwm = 0;
+    _sign = 0;
+}
+
+float Motor::stop(float duty) {
+    if (_brakeable == 1) {
+        _fwd = 1;
+        _rev = 1;
+        _pwm = duty;
+        _sign = 0;
+        return duty;
+    } else
+        Motor::coast();
+        return -1; // error, can't brake
+}
+
+float Motor::state(void) const {
+    int fwd = _fwd.read();
+    int rev = _rev.read();
+    float pwm = _pwm.read();
+    
+    if ((fwd == rev) && (pwm > 0)) {
+        return -2;//braking
+    } else if (pwm == 0) {
+        return 2;//coasting
+    } else if ((fwd == 0) && (rev == 1)) {
+        return -pwm;//reversing
+    }  else if ((fwd == 1) && (rev == 0)) {
+        return pwm;//fowards
+    } else
+        return -3;//error
+}
+
+//test code, this demonstrates working motor drivers.
+
+//Motor A(p22, p6, p5, 1); // pwm, fwd, rev, can break
+/*
+Motor A(p22, p7, p8, 1); // pwm, fwd, rev, can break
+Motor B(p21, p5, p6, 1); // pwm, fwd, rev, can break
+int main() {
+    for (float s=-1.0; s < 1.0 ; s += 0.01) {
+       //A.speed(s);
+       A.speed(s);
+       B.speed(s);
+       wait(0.02);
+    }
+    A.stop(0);
+    B.stop(0);
+    wait(1);
+    A.coast();
+    B.coast();
+}
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motordriver.h	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,91 @@
+/*motor driver libary modified from the following libary,
+*  
+* mbed simple H-bridge motor controller
+* Copyright (c) 2007-2010, sford
+* 
+* by Christopher Hasler.
+* 
+* from sford's libary,
+*
+* 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 MBED_MOTOR_H
+#define MBED_MOTOR_H
+ 
+#include "mbed.h"
+ 
+/** Interface to control a standard DC motor 
+* with an H-bridge using a PwmOut and 2 DigitalOuts
+*/
+class Motor {
+    public:
+ 
+/** Create a motor control interface    
+*
+* @param pwm A PwmOut pin, driving the H-bridge enable line to control the speed
+* @param fwd A DigitalOut, set high when the motor should go forward
+* @param rev A DigitalOut, set high when the motor should go backwards
+* @param set if the motor driver is able to do braking 0 false 1 true.
+*/
+        Motor(PinName pwm, PinName fwd, PinName rev, bool brakeable = false);
+  
+/** Set the speed of the motor 
+* 
+* @param speed The speed of the motor as a normalised value between -1.0 and 1.0.
+* @return the applied speed to the motor after checking to ensure motor doesn't switch from forward to reverse without stopping.
+*/
+        float speed(float speed);
+        
+/** Set the the motor to coast
+* 
+* @param void 
+* @return motor coasts until another instruction is recived.
+*/        
+  
+        void coast(void);
+
+/** Set the motor to dynamicaly brake
+* 
+* @param float 0 - 1.0 provides some control over how hard the motor brakes. 
+* @return duty applied to motor driver. -1 is error, motor driver can't brake.
+*/
+
+        float stop(float duty);
+/** return the current state of the motor
+*
+* @param void
+* @return state of motor, -1 to 1 is speed, -2 is braking, 2 is coasting. -3 is error. 
+*/
+        float state(void) const;
+        
+    protected:
+        mutable PwmOut _pwm;
+        mutable DigitalOut _fwd;
+        mutable DigitalOut _rev;
+        bool _brakeable; // cna the motor driver break
+        int _sign; //prevents throwing the motor from full foward to full reverse and stuff melting.
+ 
+};
+
+
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myBlueUSB.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/networker/code/myBlueUSB/#57f7679dd651
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myUSBHost.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/networker/code/myUSBHost/#74fd0a8f9d02
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/neighbourhood.cpp	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,69 @@
+#include "Utils.h"
+#include "neighbourhood.h"
+
+neighbourhood *neighbors = 0;
+
+int neighbourhood::get(BD_ADDR *a, unsigned char *key) {
+    for (list<item>::iterator i = keys.begin(); i != keys.end(); i++)
+        if (memcmp(a, &(*i).a, sizeof(BD_ADDR)) == 0) {
+            memcpy(key, (*i).lk, lksize);
+#ifdef STRICT_MRU
+            if (i != keys.begin()) {
+                keys.push_front(*i);
+                keys.erase(i);
+                dirty = true;
+            }
+#endif
+            return 1;
+        }
+    return 0;
+}
+
+int neighbourhood::add(BD_ADDR *a, const unsigned char *key, bool init) {
+    for (list<item>::iterator i = keys.begin(); i != keys.end(); i++)
+        if (memcmp(a, &(*i).a, sizeof(BD_ADDR)) == 0) {
+            memcpy((*i).lk, key, lksize); //assume key has changed, update key
+            (*i).used = true;
+            return 1;
+        }
+    //new key
+    printf("Neighbourhood: "); printf(a); printf("\n");
+    if (keys.size() < cap) {
+        keys.push_back(item(a, key, !init));//append as long as there is space
+    } else {
+        keys.push_front(item(a, key, true));//otherwise prepend
+        dirty = true;
+    }
+    return 0;
+}
+
+void neighbourhood::write() {
+    int n = 0;
+    static const int maxkey = 11;
+    unsigned char param[maxkey*(lksize+sizeof(BD_ADDR))+1];
+    int k = keys.size()-cap;
+    list<item>::iterator i = keys.begin();
+    while (i != keys.end()) {
+        if (k>0) {
+            if (!(*i).used) {
+                delete_link_key(&(*i).a);//try to make some room
+                keys.erase(i);
+                k--;
+            } else
+                i++;
+        } else
+            break;
+    }
+    //hci->delete_link_keys();
+    unsigned char *p = &param[1];
+    for (list<item>::iterator i = keys.begin(); i != keys.end() && n<maxkey; i++, n++) {
+        memcpy(p, &(*i).a, sizeof(BD_ADDR));
+        p += sizeof(BD_ADDR);
+        memcpy(p, (*i).lk, lksize);
+        p += lksize;
+    }
+    param[0] = n;
+    if (n > 0)
+       write_link_keys(param);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/neighbourhood.h	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,77 @@
+#ifndef NEIGHBOURHOOD_H
+#define NEIGHBOURHOOD_H
+
+#include <list>
+#include "hci.h"
+
+//#define STRICT_MRU
+
+/******************************************************************************************
+call 'read' as part of the startup
+on HCI_READ-STORED-LINK-KEY -COMPLETED event,  call 'set_cap'
+on RETURN_LINK_KEYS_EVENT call 'add' for each key with init=true
+on LINK_KEY_NOTIFICATION_EVENT call 'add' with init=false (default)
+on LINK_KEY_REQUEST_EVENT call 'get' and send the proper reply
+call 'write' as part of shutdown
+
+a simpler approach could be to check for a link if it exists (single read) and try to add it.
+when it fails just delete all.
+********************************************************************************************/
+
+#define HCI_DELETE_STORED_LINK_KEY  0x0C12
+#define HCI_WRITE_STORED_LINK_KEY   0x0C11
+#define HCI_READ_STORED_LINK_KEY    0x0C0D
+
+void printf(const BD_ADDR* addr);
+
+class neighbourhood {
+    static const int lksize = 16;
+    struct item {
+        BD_ADDR a;
+        unsigned char lk[lksize];
+        bool used;
+        item (BD_ADDR *ad, const unsigned char *k, bool d) {
+            memcpy(&a, ad, sizeof(BD_ADDR));
+            memcpy(lk, k, lksize);
+            used=d;
+        }
+    };
+    int cap, initsize, used;
+    list<item> keys;
+    bool dirty;
+    HCI *hci;
+    void delete_link_key(BD_ADDR *a) {
+        unsigned char param[sizeof(BD_ADDR)+1];
+        memcpy(param, a, sizeof(BD_ADDR));
+        param[sizeof(BD_ADDR)] = 0;
+        hci->SendCmd(HCI_DELETE_STORED_LINK_KEY, param, sizeof(param));
+    }
+    void write_link_keys(unsigned char param[]) {
+        hci->SendCmd(HCI_WRITE_STORED_LINK_KEY, param, param[0]*(sizeof(BD_ADDR)+lksize)+1);
+    }
+public:
+    neighbourhood(HCI *h): hci(h) {
+        dirty = false;
+        used = 0;
+        cap=0;
+        initsize=0;
+    }
+    void read() {
+        unsigned char param[sizeof(BD_ADDR)+1];
+        memset(param, 0, sizeof(BD_ADDR));
+        param[sizeof(BD_ADDR)] = 1;
+        hci->SendCmd(HCI_READ_STORED_LINK_KEY, param, sizeof(param));
+    }
+    void write();
+    void set_cap(int c, int s) {
+        cap = c;
+        initsize = s;
+        printf("Neighbourhood: capacity=%d, used=%d\n", c, s);
+    }
+    int get(BD_ADDR *a, unsigned char *key);
+    int add(BD_ADDR *a, const unsigned char *key, bool init=false);
+};
+
+extern neighbourhood *neighbors;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rfcomm.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/networker/code/rfcomm/#1c90839a1e70
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp.lib	Tue Jul 05 08:25:59 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/networker/code/sdp/#d5c3e499603d