class library to access fischertechnik interfaces via USB

Dependencies:   FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp

ftlib/ftusb.cpp

Committer:
networker
Date:
2013-03-11
Revision:
1:4676e8b9b357
Parent:
0:7da612835693

File content as of revision 1:4676e8b9b357:

#include "mbed.h"
#include "USBHost.h"
#include "ftusb.h"
#include <vector>
#include "Utils.h"
#include "HCITransportUSB.h"
#include "Socket.h"
#include "RFCOMM.h"
#include "sdp.h"
#include "neighbourhood.h"

//  these should be placed in the DMA SRAM
typedef struct {
    u8 _hciBuffer[MAX_HCL_SIZE];
    u8 _aclBuffer[MAX_ACL_SIZE];
} SRAMPlacement;

const char FtDevClass[3] = {0x00, 0x1F, 0x82 };
const char SerDevClass[3] = {4, 1, 0x00};

HCITransportUSB _HCITransportUSB;  //use USB as the transport to the radio
BTApp Bluetooth;
vector<_ftdev> devs;
bool tx_emulation = false;

void OnLoadFtDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) {
    for (int i = 0; i < devs.size(); i++)
        if (devs[i].device == device) {
            printf("device %d was already in the list\n", device);
            return;
        }
    switch (deviceDesc->idProduct) {
        case 1:
            devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber));
            printf("RoboInterface\n");
            break;
        case 2:
            devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber));
            printf("RoboExtension\n");
            break;
        case 3:
            devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber, 0));
            printf("Robo RF Interface\n");
            break;
        case 4:
            printf("Sound\n");
            break;
        case 4096:
            devs.push_back(*new _ftdev(device, deviceDesc->idProduct, deviceDesc->iSerialNumber));
            printf("TX Controller\n");
            break;
        default:
            printf("fischertechnik product %d\n", deviceDesc->idProduct);
            break;
    }
}


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,&Bluetooth); //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");
    Bluetooth.Open(&_HCITransportUSB);//the callback is virtual, calls BTApp::Callback
    Bluetooth.Inquiry();//start discovery of BT devices phase 0
    return 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]);
}

//  We have connected to a device
void BTApp::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 ft 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;
        }
    }
}

void BTApp::ConnectDevices() {
    count = GetDevices(devs,8);//get pointers to all bluetooth devices
    pending = 0;
    for (i = 0; i < count; i++) {//find first ft device (when filter works, all devices are ft devices)
        //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;
        }
    }
}

void BTApp::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv
    unsigned char pin[] = "1234";
    u8 filter[] = {0x00, 0x1F, 0x82, 0xFF, 0xFF, 0xFF };
    unsigned char ftaddr[] = {0x2c, 0x07, 0x54, 0x7b, 0x13, 0x00};//possible ft TX address (ROBO TX-277)
    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) { //spoof address
              printf("programming new spoofed address\n");
              //csr_write_bd_addr((BD_ADDR*)newaddr, false);
            }
            if (memcmp(ftaddr+3, data+3, 3) == 0) {
               tx_emulation = true;
               printf("ft BT address => TX emulation mode\n");
            }
            SetEventFilter(1, 1, filter);
            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
            break;

        case CALLBACK_INQUIRY_DONE:
            printf("CALLBACK_INQUIRY_DONE\n");
            neighbors = new neighbourhood(&Bluetooth);
            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--;
        }
        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);
            PinCodeReply(data, pin);
            break;
        default:
            printf("Unhandled HCI Callback %d\n", evt);
    };
    printf("\x1b[%dm", 0);
}

#define CSR_WRITE        0xFC00

int BTApp::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 BTApp::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));
}