class library to access fischertechnik interfaces via USB

Dependencies:   FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp

ftlib/ftlibclassusb.cpp

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

File content as of revision 1:4676e8b9b357:

#include "mbed.h"
#include "ftusb.h"
#include "ftlibclass.h"
#include "ftlibclassusb.h"
#include "ftlibclasstxc.h"

#ifdef USE_DOWNLOAD
#include "crc.h"
#endif

#define VERSION_MAJOR LIBFT_VERSION_MAJOR
#define VERSION_MINOR LIBFT_VERSION_MINOR
#define VERSION_PATCH LIBFT_VERSION_PATCH
#define ABF_IF_COMPLETE 0x8b // 0xf2
#define INTERFACE_QUERY_TIME_SERIAL 10000
#define FT_ENDPOINT_INTERRUPT_IN 0x81
#define FT_ENDPOINT_INTERRUPT_OUT 0x1
#define FT_ENDPOINT_BULK_IN 0x82
#define FT_ENDPOINT_BULK_OUT 0x2
#define FT_RF_ENDPOINT_INTERRUPT_IN 0x82
#define FT_RF_ENDPOINT_INTERRUPT_OUT 0x2
#define FT_USB_TIMEOUT 1000
#define FT_USB_TIMEOUT_LONG 10000
#define PROGRAM_UPLOAD_PACKET_SIZE 128

#define GET_MAN     1
#define GET_LONG    2
#define GET_SN      3
#define GET_FW      4
#define GET_SHORT   5

#define usleep(x)    wait_us(x)
#define sleep(x)    wait(x)

vector<ftusbdev*> ftusbdev::devs;

int ftusbdev::GetNumFtDevicesFromRF(int device) {
    unsigned iNum = 0;
    int ret;
    unsigned char buffer[35] = { 0 };
    for (int i=1; i<9; i++) {
        ret = USBControlTransfer(device, 0xc0, 0x52, i<<8 | 0x05, 0, buffer, 35, 0, 0);
        if (ret < 0) {
            fprintf(stderr, "Error sending control msg 0xC0 0x52\n");
            return ret;
        } else if (buffer[0] == 0xfa && buffer[1] == 0) { // buffer[1] == 0xff => no device
            iNum++;
            unsigned snr = *(unsigned*)(buffer+3); //buffer[3] + buffer[4]*100 + buffer[5]*10000 + buffer[6]*1000000;
            ftusbdev *d = new ftusbdev(device, FT_ROBO_IF_OVER_RF, snr, i);
            d->fw = *(unsigned*)(buffer+20);
            devs.push_back(d);//use datalink as type and assume little endianness
        }
    }
    return iNum;
}

unsigned ftusbdev::InitFtUsbDeviceList() {
    char buffer[128];
    devs.clear();
    for (vector<_ftdev>::iterator i = ::devs.begin(); i < ::devs.end(); i++) {
        unsigned sn = 0;
        if (i->product == 0x1000) { //TXC
            devs.push_back(new ftusbdevtx(i->device));
            continue;
        }
        if (GetString(i->device, GET_SN, buffer, 18) >= 0) {
            sn = atoi(buffer);
        } else {
            printf("device %d did not respond\n", i->device);
            continue;
        }
        if (i->product == RF_DATA_LINK_PRODUCT_ID) {//robo over RF
            ftusbdev *dl = new ftusbdev(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn, 0); //the RF call ID of the link is 0 but this is useless
            devs.push_back(dl);
            int pos = devs.size(); //position of first appended RF interface
            int n = GetNumFtDevicesFromRF(i->device);
            if (n > 0) {
                dl->rf = devs[pos]->rf; //use the rf of the first child
            }
        } else {
            if (i->product == EXT_IF_PRODUCT_ID)
                devs.push_back(new ftusbdevext(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn));
            else
                devs.push_back(new ftusbdev(i->device, ftlib::FtproductIDToInterfaceID(i->product), sn));
        }
    }
    return FTLIB_ERR_SUCCESS;
}


ftusbdev* ftusbdev::GetFtUsbDeviceHandle(unsigned  Num) {
    if (Num < devs.size()) {
        return devs[Num];
    }
    return 0;
}

ftusbdev* ftusbdev::GetFtUsbDeviceHandleSerialNr(unsigned dwSN, unsigned dwTyp) {
    for (int i = 0; i < devs.size(); i++)
        if (devs[i]->sn == dwSN) {
            if (dwTyp == 0 || dwTyp == devs[i]->type)
                return GetFtUsbDeviceHandle(i);
        }
    fprintf(stderr, "GetFtUsbDeviceSerialNr(%d, %d) not found\n", dwSN, dwTyp);
    return 0;
}

unsigned ftusbdev::OpenFtUsbDevice() {
    FT_TRANSFER_AREA *area = new FT_TRANSFER_AREA;
    memset(area, 0, sizeof(struct _FT_TRANSFER_AREA));
    area->RfModulNr = rf;
    area->TransferAktiv = 0;
    ta = area;
    return 0;
}

unsigned ftusbdev::CloseFtDevice() {
    if (ta==0)
      return FTLIB_ERR_DEVICE_NOT_OPEN;
    while (ta->TransferAktiv != 0) {
        fprintf(stderr, "Transfer ta still active\n");
        sleep(1);
    }
    delete ta;
    ta = 0;
    return 0;
}

unsigned ftusbdev::GetFtFirmware() {
    int ret;
    unsigned char buffer[35] = { 0 };
    if (fw > 0)
        return fw;
    switch (type) {
        case FT_ROBO_IF_USB:
        case FT_ROBO_IO_EXTENSION:
        case FT_ROBO_RF_DATA_LINK:
            ret = USBControlTransfer(device, 0xc0, 0xf0, 0x1, 0, buffer, 5);
            if (ret < 0) {
                fprintf(stderr, "Error sending control msg 0xC0 0xF0\n");
                return 0;
            }
            fw = buffer[1] | buffer[2]<<8 | buffer[3]<<16 | buffer[4]<<24;
            break;
        case FT_ROBO_IF_OVER_RF:
            ret = USBControlTransfer(device, 0xc0, 0x52, rf<<8 | 0x05, 0, buffer, 35);
            if (ret < 0) {
                fprintf(stderr, "Error sending control msg 0xC0 0x52\n");
                return 0;
            }
            if (buffer[0] == 0xfa && buffer[1] == 0) { // buffer[1] == 0xff => no device
                fw = buffer[23]<<24 | buffer[22]<<16 | buffer[21]<<8 | buffer[20];
            }
            break;
        default:
            return FTLIB_ERR_NOT_SUPPORTED;
    }
    return fw;
}

char * ftusbdev::GetFtLongNameStrg() {
    const int sz = 128;
    char *buffer = new char[sz];
    buffer[0] = '\0';

    switch (type) {
        case FT_ROBO_IF_USB:
        case FT_ROBO_RF_DATA_LINK:
        case FT_ROBO_IO_EXTENSION:
            GetString(device, GET_LONG, buffer, sz);
            break;
        case FT_ROBO_IF_OVER_RF:
            sprintf(buffer, " Robo Interface (RF:%d)", rf);
            break;
    }
    return buffer;
}

char * ftusbdev::GetFtShortNameStrg() {
    const int sz = 128;
    char *buffer = new char[sz];
    buffer[0] = '\0';

    switch (type) {
        case FT_ROBO_IF_USB:
        case FT_ROBO_RF_DATA_LINK:
        case FT_ROBO_IO_EXTENSION:
            GetString(device, GET_SHORT, buffer, sz);
            break;
        case FT_ROBO_IF_OVER_RF:
            sprintf(buffer, " (RF:%d)", rf);
            break;
    }
    return buffer;
}

char * ftusbdev::GetFtManufacturerStrg() {
    const int sz = 128;
    char *buffer = new char[sz];
    buffer[0] = '\0';
    GetString(device, GET_MAN, buffer, sz);
    return buffer;
}

void ftusbdev::poll() {
    for (int i = 0; i < devs.size(); i++) {
        if (devs[i]->triggered) {
            if (devs[i]->guardedFtThreadBegin())
                devs[i]->triggered = 0;
        }
    }
    //USBLoop();
}

void ftusbdev::FtThreadInit() {//setup buffers for this type of interface
    num_write = ABF_IF_COMPLETE_NUM_WRITE;
    num_read = ABF_IF_COMPLETE_NUM_READ;
    out[0] = ABF_IF_COMPLETE;
    ftdev::FtThreadInit();
    unsigned ret;
    switch (type) {
        case FT_ROBO_IF_OVER_RF:
        case FT_ROBO_RF_DATA_LINK:
            usb_endpoint_write = FT_RF_ENDPOINT_INTERRUPT_OUT;
            usb_endpoint_read = FT_RF_ENDPOINT_INTERRUPT_IN;
            ret = USBControlTransfer(device, 0xc0, 0xfb, rf << 8 | 0x02, 0x1, in, 2, 0, 0);
            if (ret != 2) {
                fprintf(stderr, "%d FtThread: Error initiating RF Module!\n");
                //ta->TransferAktiv = 0;
            }
            break;
        default: //FT_ROBO_USB
            usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT;
            usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN;
            break;
    }
}

void ftusbdev::read_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) {
//end of reply transfer
    ftusbdev *fth = (ftusbdev*)userData;
    fth->FtThreadEnd();
}

void ftusbdev::write_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { //end of request transfer, issue, reply transfer
    ftusbdev *fth = (ftusbdev*)userData;
    USBInterruptTransfer(fth->device, fth->usb_endpoint_read, fth->in, fth->num_read, read_finished_cb, fth);
}

//here the real data exchange starts
void ftusbdev::FtThreadBegin() {//called every 10ms to issue a request, should be non-blocking
    if (!test_and_set()) {//return when transferarea is in use
        busy = false; //release the mutex, otherwise the thread effectively stops
        return;//return because there is no point in sending a nonsense request, alternatively the lock can be ignored in which case the data may be inconsistent
    }
//putc('(', stderr);
    out[1] = ta->M_Main;
    out[2] = (ta->MPWM_Main[0] & 0x7) | (ta->MPWM_Main[1]<<3 & 0x38) | (ta->MPWM_Main[2]<<6 & 0xC0);
    out[3] = (ta->MPWM_Main[2] & 0x1) | (ta->MPWM_Main[3]<<1 & 0xE) | (ta->MPWM_Main[4]<<4 & 0x70) | (ta->MPWM_Main[5]<<7 & 0x80);
    out[4] = (ta->MPWM_Main[5] & 0x3) | (ta->MPWM_Main[6]<<2 & 0x1C) | (ta->MPWM_Main[7]<<5 & 0xE0);
    out[5] = ta->M_Sub1;
    out[6] = (ta->MPWM_Sub1[0] & 0x7) | (ta->MPWM_Sub1[1]<<3 & 0x38) | (ta->MPWM_Sub1[2]<<6 & 0xC0);
    out[7] = (ta->MPWM_Sub1[2] & 0x1) | (ta->MPWM_Sub1[3]<<1 & 0xE) | (ta->MPWM_Sub1[4]<<4 & 0x70) | (ta->MPWM_Sub1[5]<<7 & 0x80);
    out[8] = (ta->MPWM_Sub1[5] & 0x3) | (ta->MPWM_Sub1[6]<<2 & 0x1C) | (ta->MPWM_Sub1[7]<<5 & 0xE0);
    out[9] = ta->M_Sub2;
    out[10] = (ta->MPWM_Sub2[0] & 0x7) | (ta->MPWM_Sub2[1]<<3 & 0x38) | (ta->MPWM_Sub2[2]<<6 & 0xC0);
    out[11] = (ta->MPWM_Sub2[2] & 0x1) | (ta->MPWM_Sub2[3]<<1 & 0xE) | (ta->MPWM_Sub2[4]<<4 & 0x70) | (ta->MPWM_Sub2[5]<<7 & 0x80);
    out[12] = (ta->MPWM_Sub2[5] & 0x3) | (ta->MPWM_Sub2[6]<<2 & 0x1C) | (ta->MPWM_Sub2[7]<<5 & 0xE0);
    out[13] = ta->M_Sub3;
    out[14] = (ta->MPWM_Sub3[0] & 0x7) | (ta->MPWM_Sub3[1]<<3 & 0x38) | (ta->MPWM_Sub3[2]<<6 & 0xC0);
    out[15] = (ta->MPWM_Sub3[2] & 0x1) | (ta->MPWM_Sub3[3]<<1 & 0xE) | (ta->MPWM_Sub3[4]<<4 & 0x70) | (ta->MPWM_Sub3[5]<<7 & 0x80);
    out[16] = (ta->MPWM_Sub3[5] & 0x3) | (ta->MPWM_Sub3[6]<<2 & 0x1C) | (ta->MPWM_Sub3[7]<<5 & 0xE0);
    out[17]    = 0;
    if (messages && messages->nrOfMessages()>0) {
        out[18]    = 0;
        *(SMESSAGE*)(out+19) = messages->pop();
    } else {
        memset(out+18, 0, 7);
    }
    if (messages && messages->nrOfMessages()>0) {
        out[25]    = 0;
        *(SMESSAGE*)(out+26) = messages->pop();
    } else {
        memset(out+25, 0, 7);
    }
    increment();//release the lock on shared memeory
    USBInterruptTransfer(device, usb_endpoint_write, out, num_write, write_finished_cb, this); //return immediately and call the callback when finished
}
#if 0 //use the parent version
void ftusbdev::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete
    if (!test_and_set()) {//skip when busy
        busy = false;
        return;
    }
    ta->ChangeEg = ta->E_Main != in[0] || ta->E_Sub1 != in[1] || ta->E_Sub2 != in[2] || ta->E_Sub3 != in[3];
    ta->E_Main = in[0];
    ta->E_Sub1 = in[1];
    ta->E_Sub2 = in[2];
    ta->E_Sub3 = in[3];
    ta->ChangeAn = 1; //assume that analog always changes (noise)
    ta->AX = in[4];
    ta->AY = in[5];
    ta->A1 = in[6];
    ta->A2 = in[7];
    ta->AX |= (in[8] & 0x3) << 8;
    ta->AY |= (in[8] & 0xC) << 6;
    ta->A1 |= (in[8] & 0x30) << 4;
    ta->A2 |= (in[8] & 0xC0) << 2;
    ta->AZ = in[9];
    ta->D1 = in[10];
    ta->D2 = in[11];
    ta->AV = in[12];
    ta->AZ |= (in[13] & 0x3) << 8;
    ta->D1 |= (in[13] & 0xC) << 6;
    ta->D2 |= (in[13] & 0x30) << 4;
    ta->AV |= (in[13] & 0xC0) << 2;
    if (ta->IRKeys != in[14])
        ta->ChangeIr = 1;
    ta->IRKeys = in[14];
    ta->BusModules = in[15];
    // 16
    ta->AXS1 = in[17];
    ta->AXS2 = in[18];
    ta->AXS3 = in[19];
    ta->AXS1 |= (in[20] & 0x3) << 8;
    ta->AXS2 |= (in[20] & 0xC) << 6;
    ta->AXS3 |= (in[20] & 0x30) << 4;
    // 21
    ta->AVS1 = in[22];
    ta->AVS2 = in[23];
    ta->AVS3 = in[24];
    ta->AVS1 |= (in[25] & 0x3) << 8;
    ta->AVS2 |= (in[25] & 0xC) << 6;
    ta->AVS3 |= (in[25] & 0x30) << 4;
    // 26...42
    ta->AV *= 3;
    ta->AVS1 *= 3;
    ta->AVS2 *= 3;
    ta->AVS3 *= 3;
    //message processing
    if (messages && ne.CallbackMessage) { //just to check if communication was enabled
        if (in[28])
            ne.CallbackMessage((SMESSAGE*)(in+29));
        if (in[35])
            ne.CallbackMessage((SMESSAGE*)(in+36));
    }
    increment();
    interface_connected = 1;
    if (ne.NotificationCallback) {
        (*ne.NotificationCallback)(ne.Context);
    }
    busy = false;
}
#endif

void ftusbdev::FtThreadFinish() {//called by StopFtTransferArea
    if (type == FT_ROBO_IF_OVER_RF || type == FT_ROBO_RF_DATA_LINK) {
        int ret = USBControlTransfer(device, 0xc0, 0x21, rf << 8, 0, in, 1);
        if (ret != 1 || in[0] != 0xd7) {
            fprintf(stderr, "Error uninitiating RF Module!\n");
        }
    }
    ftdev::FtThreadFinish();
}

unsigned ftusbdev::SetFtDeviceCommMode (unsigned dwMode, unsigned dwParameter, unsigned short *puiValue) {
    unsigned char buf[3];
    unsigned  ret = USBControlTransfer(device, 0xc0, 0xf0, 0x0040, dwMode|(dwParameter<<8), buf, 3);
    if (puiValue && dwMode == IF_COM_PARAMETER)
        *puiValue = buf[1];
    return ret;
}

void ftusbdevext::FtThreadInit() {//setup buffers for this type of interface
    usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT;
    usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN;
    ftdev::FtThreadInit();
    out[0] = 0xf2;
    num_write = 6;
    num_read = 6;
}

void ftusbdevext::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete
    if (!test_and_set()) {//skip when busy
        busy = false;
        return;
    }
    ta->ChangeEg = ta->E_Main != in[0];
    ta->E_Main = in[0];
    ta->ChangeAn = 1; //assume that analog always changes (noise)
    ta->AX = in[1];
    ta->A1 = in[2];
    ta->AV = in[3];
    ta->AX |= (in[4] & 0x3) << 8;
    ta->A1 |= (in[4] & 0xC) << 6;
    ta->AV |= (in[4] & 0x30) << 4;
    ta->AV *= 3;
    increment();
    interface_connected = 1;
//printf("%02X) ", ta->E_Main);
    if (ne.NotificationCallback) {
//        printf("%02X\r", transfer_area.E_Main);
        (*ne.NotificationCallback)(ne.Context);
    }
    busy = false;
}

unsigned ftusbdev::SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, unsigned dwLevel1, unsigned dwLevel2, unsigned dwRepeat1, unsigned dwRepeat2) {
    int ret;
    unsigned char buffer[] =  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 34

    buffer[1] = dwTol1;
    buffer[2] = dwTol2;
    buffer[3] = dwLevel1;
    buffer[4] = dwLevel1>>8;
    buffer[5] = dwLevel2;
    buffer[6] = dwLevel2>>8;
    buffer[7] = dwRepeat1;
    buffer[8] = dwRepeat2;

    switch (type) {
        case FT_ROBO_IF_USB:
            ret = USBControlTransfer(device, 0x40, 0xf1, 0x1, dwMode, buffer+1, 8);
            if (ret != 8) {
                fprintf(stderr, "Error sending control msg 0x40 0xf1\n");
                return ret;
            }
            break;
        case FT_ROBO_RF_DATA_LINK:
        case FT_ROBO_IF_OVER_RF:
            ret = USBControlTransfer(device, 0x40, 0x53, rf<<8 | 0x01, 0, buffer, 34);
            if (ret != 34) {
                fprintf(stderr, "Error sending control msg 0x40 0x53\n");
                return ret;
            }
            break;
        default:
            return FTLIB_ERR_NOT_SUPPORTED;
    }
    usleep(100000); // wait before continue, else it doesn't always work
    return FTLIB_ERR_SUCCESS;
}

unsigned ftusbdev::pgm_message(unsigned code, unsigned dwMemBlock) {
    unsigned char buffer[2];
    if (type != FT_ROBO_IF_USB) return FTLIB_ERR_NOT_SUPPORTED;
    int ret = USBControlTransfer(device, 0xc0, code, dwMemBlock, 0, buffer, 1);
    if (ret < 0) {
        fprintf(stderr, "Error sending control msg 0xC0 %02X\n", code);
        return ret;
    }
    if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS;
    else return FTLIB_ERR_IF_NO_PROGRAM;
}