class library to access fischertechnik interfaces via USB

Dependencies:   FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp

Revision:
0:7da612835693
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ftlib/ftlibclassusb.cpp	Wed Jun 15 19:12:25 2011 +0000
@@ -0,0 +1,454 @@
+#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;
+}