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/ftlibclasscom.cpp	Wed Jun 15 19:12:25 2011 +0000
@@ -0,0 +1,456 @@
+#include "mbed.h"
+#include "ftlibclasscom.h"
+vector<ftcommdev*> ftcommdev::devs;
+
+ftcommdev::ftcommdev(Serial *s, unsigned t, unsigned c): ftdev(t, 0) {
+    device = s;
+    port = 0;
+    FT_TRANSFER_AREA *area = new FT_TRANSFER_AREA;
+    memset(area, 0, sizeof(struct _FT_TRANSFER_AREA));
+    area->TransferAktiv = 0;
+    //query_time = INTERFACE_QUERY_TIME_SERIAL;
+    area->RfModulNr = -1;
+    if (t == FT_INTELLIGENT_IF)
+        area->BusModules = 1;
+    else if (t == FT_INTELLIGENT_IF_SLAVE)
+        area->BusModules = 2;
+    ta = area;
+}
+
+//blocking
+int ftcommdev::read(Serial *stream, unsigned char *buf, int n, int timeout_ms) {
+    Timer t;
+    t.start();
+    int i = 0;
+    while (t.read_ms() < timeout_ms && i < n) {
+        if (stream->readable())
+            buf[i++] = stream->getc();
+    }
+    return i;
+}
+
+int ftcommdev::write(Serial *d, unsigned char *ptr, int n, int timeout_ms) {
+    Timer t;
+    t.start();
+    int i = 0;
+    while (t.read_ms() < timeout_ms && i < n) {
+        if (d->writeable())
+            d->putc(ptr[i++]);
+    }
+    return i;
+}
+
+//non-blocking
+int ftcommdev::write() {
+    windex = 0;
+    writeByte(); //write the first byte, callback will take care of the rest
+    return num_write;
+}
+void ftcommdev::writeByte() {
+    if (windex < num_write) {
+        device->putc(out[windex++]);
+        if (windex == num_write)
+            rindex = 0;
+    }
+}
+void ftcommdev::readByte() {
+    if (rindex < num_read) {
+        in[rindex++] = device->getc();
+        if (rindex == num_read) {
+            FtThreadEnd();
+        }
+    }
+}
+
+ftcommdev* ftcommdev::OpenFtCommDevice(unsigned sDevice, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError) {//makes a (blocking) comm request to the interface
+    Serial *dev = 0;
+    switch (sDevice) {
+        case 1:
+            dev = new Serial(p9, p10);
+            break;
+        case 2:
+            dev = new Serial(p13, p14);
+            break;
+        case 3:
+            dev = new Serial(p28, p27);
+            break;
+//      default:  dev = new Serial(p9, p10); break;
+        default:
+//            dev = &viaUsb;
+            break;
+    }
+    ftcommdev* com = OpenFtCommDevice(dev, dwTyp, dwZyklus, pdwError);
+    if (com) {
+        com->port = sDevice;
+        printf("opening of COM%d OK\n", sDevice);
+    }
+    return com;
+}
+
+ftcommdev* ftcommdev::OpenFtCommDevice(Serial *dev, unsigned dwTyp, unsigned dwZyklus, unsigned *pdwError) {//makes a (blocking) comm request to the interface
+    unsigned char in[5];
+    unsigned char on[] = " ft-Robo-ON-V1";
+    on[0] = 0xA1;
+    ftcommdev* ret = 0;
+    if (dwTyp != FT_ROBO_IF_COM) {
+        ret = new ftcommdevii(dev, dwTyp, dwZyklus);
+        dev->baud(BAUDRATE_II);
+    } else {// dwTyp == FT_ROBO_IF_COM
+        ret = new ftcommdev(dev, dwTyp, dwZyklus);
+        dev->baud(BAUDRATE_RI);
+    }
+    printf("about to send '%s'\n", on);
+    if (dwTyp == FT_ROBO_IF_COM) {
+        int sent = write(dev, on, strlen((const char*)on), 100/*ms*/);
+//        int sent = dev->printf("%s", on);
+        printf("sent %d bytes to COM\n", sent);
+        if (sent == strlen((const char*)on)) {
+            if (read(dev, in, 5, 1000/*ms*/) == 5) {              //   if (dev->scanf("%5c", in) == 1) { does not work, could have to do with NUL chars or needs a lookahead char
+                printf("%02X: interface version: %d.%d.%d.%d\n", in[0], in[4], in[3], in[2], in[1]);
+                ret->fw = *(unsigned*)(in+1);
+                if ((in[0] ^ on[0]) ==  0x0FFU) {
+                    printf("opening of %s OK\n", "UNKNOWN");
+                } else {
+                    printf("return code is %02X but should be %02X\n", in[0], ~on[0]&0xFF);
+                    delete ret;
+                    return NULL;
+                }
+            } else {
+                printf("read did not return 5\n");
+                delete ret;
+                return NULL;
+            }
+        } else {
+            printf("only %d chars were sent i.o %d\n", sent, strlen((const char*)on));
+            delete ret;
+            return NULL;
+        }
+    }
+    devs.push_back(ret);
+    return ret;
+}
+
+unsigned ftcommdev::CloseFtDevice() {//sends a comm request
+    unsigned char off = 0xA2;
+    unsigned char in[1];
+
+    while (ta->TransferAktiv != 0) {
+        fprintf(stderr, "Transfer ta still active\n");
+        sleep(1);
+    }
+
+    if (type == FT_ROBO_IF_COM) {
+        if (write(device, &off, 1, 500) != 1 || read(device, in, 1, 1000) != 1 || (in[0]^off != 0xFF)) {
+            fprintf(stderr, "CloseFtDevice: Error communicating with serial\n");
+        }
+    }
+    for (vector<ftcommdev*>::iterator it = devs.begin(); it < devs.end(); it++)
+        if (*it == this) {
+            devs.erase(it);
+            delete this;
+            return 0;
+        }
+    return 0;
+}
+
+unsigned ftcommdev::GetFtSerialNr() {
+    int ret;
+    unsigned char buffer[35] = { 0 };
+    if (sn > 0)
+        return sn;
+    switch (type) {
+        case FT_INTELLIGENT_IF:
+        case FT_INTELLIGENT_IF_SLAVE:
+            return 0;
+        case FT_ROBO_IF_COM:
+            buffer[0] = 0xf0;
+            buffer[1] = 0x02;
+            ret = write(device, buffer, 2, 500);
+            if (ret != 2) {
+                fprintf(stderr, "Error writing msg 0xF0 0x02\n");
+                return 0;
+            }
+            ret = read(device, buffer, 5, 1000);
+            if (ret != 5) {
+                fprintf(stderr, "Error reading msg 0xF0 0x02\n");
+                return 0;
+            }
+            //sn = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000;
+            sn = *(unsigned*)(buffer+1);
+            break;
+        default:
+            return FTLIB_ERR_NOT_SUPPORTED;
+    }
+    return sn;
+}
+
+char * ftcommdev::GetFtLongNameStrg() {
+    switch (type) {
+        case FT_INTELLIGENT_IF:
+            return strdup("Intelligent Interface");
+        case FT_INTELLIGENT_IF_SLAVE:
+            return strdup("Intelligent Interface with Slave");
+        case FT_ROBO_IF_IIM:
+            return strdup("Robo Interface in Intelligent Interface mode");
+        case FT_ROBO_IF_COM:
+            return strdup("Robo Interface on Com");
+        default:
+            return strdup("Unknown interface type");
+    }
+}
+
+char * ftcommdev::GetFtShortNameStrg() {
+    switch (type) {
+        case FT_INTELLIGENT_IF:
+            return strdup("IIF");
+        case FT_INTELLIGENT_IF_SLAVE:
+            return strdup("IIF w/Slave");
+        case FT_ROBO_IF_IIM:
+            return strdup("RI_IIM");
+        case FT_ROBO_IF_COM:
+            return strdup("RICom");
+        default:
+            return strdup("Unknown");
+    }
+}
+
+void ftcommdev::poll() {
+    for (int i = 0; i < devs.size(); i++) {
+        if (devs[i]->triggered) {
+            if (devs[i]->guardedFtThreadBegin())
+                devs[i]->triggered = 0;
+        }
+    }
+}
+
+void ftcommdev::FtThreadInit() {//setup buffers for this type of interface
+    device->attach(this, &ftcommdev::writeByte, Serial::TxIrq);
+    device->attach(this, &ftcommdev::readByte, Serial::RxIrq);
+    ftdev::FtThreadInit();
+    out[0] = 0xf2;
+    num_write = 17;
+    num_read = 21;
+}
+
+//here the real data exchange starts
+void ftcommdev::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
+    }
+    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;
+    out[18]    = 0;
+    out[19]    = 0;
+    out[20]    = 0;
+    out[21]    = 0;
+    out[22]    = 0;
+    out[23]    = 0;
+    out[24]    = 0;
+    out[25]    = 0;
+    out[26]    = 0;
+    out[27]    = 0;
+    out[28]    = 0;
+    out[29]    = 0;
+    out[30]    = 0;
+    out[31]    = 0;
+
+    increment();//release the lock on shared memeory
+    write();
+}
+#if 0
+void ftcommdev::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
+    increment();
+    interface_connected = 1;
+    if (ne.NotificationCallback) {
+        (*ne.NotificationCallback)(ne.Context);
+    }
+    busy = false;
+}
+#endif
+
+void ftcommdev::FtThreadFinish() {//called by StopFtTransferArea
+    device->attach(0,Serial::RxIrq);
+    device->attach(0,Serial::TxIrq);
+    ftdev::FtThreadFinish();
+}
+
+void ftcommdevii::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
+    }
+    out[1] = ta->M_Main;
+    out[2] = ta->M_Sub1;
+
+    // For the II we need to simulate different speeds here
+    for (int iCurMotor = 0; iCurMotor < 7; iCurMotor++) {
+        if (ta->MPWM_Main[iCurMotor] < ii_speed) out[1] &= ~(1 << iCurMotor);
+        if (ta->MPWM_Sub1[iCurMotor] < ii_speed) out[2] &= ~(1 << iCurMotor);
+    }
+    ii_speed++;
+    if (ii_speed > 7) ii_speed = 0;
+
+    num_write=2;
+    switch (cycle) {
+        case 0:
+            num_read=3;
+            out[0] = 0xc5;
+            break;
+        case 1:
+            num_read=3;
+            out[0] = 0xc9;
+            break;
+        default:
+            num_read=1;
+            out[0] = 0xc1;
+            break;
+    }
+    if (type == FT_INTELLIGENT_IF_SLAVE) {
+        num_write++;
+        num_read++;
+        out[0]++;
+    }
+    if (cycle++ > analogcycle) cycle=0;
+    increment();//release the lock on shared memeory
+    write();
+}
+
+void ftcommdevii::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->BusModules = type==FT_INTELLIGENT_IF_SLAVE;
+    switch (out[0]) {
+        case 0xc1:
+            break;
+        case 0xc5:
+            ta->AX = in[1] | (8<<in[2]);
+            break;
+        case 0xc9:
+            ta->AY = in[1] | (8<<in[2]);
+            break;
+        case 0xc2:
+            ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1];
+            ta->E_Sub1 = in[1];
+            break;
+        case 0xc6:
+            ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1];
+            ta->E_Sub1 = in[1];
+            ta->AX = in[2] | (8<<in[3]);
+            break;
+        case 0xca:
+            ta->ChangeEg = ta->ChangeEg || ta->E_Sub1 != in[1];
+            ta->E_Sub1 = in[1];
+            ta->AY = in[2] | (8<<in[3]);
+            break;
+    }
+    increment();
+    interface_connected = 1;
+    if (ne.NotificationCallback) {
+        (*ne.NotificationCallback)(ne.Context);
+    }
+    busy = false;
+}
+
+unsigned ftcommdev::SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2, unsigned dwLevel1, unsigned dwLevel2, unsigned dwRepeat1, unsigned dwRepeat2) {
+    unsigned char buffer[11];
+ 
+    if (type != FT_ROBO_IF_COM)
+        return FTLIB_ERR_NOT_SUPPORTED;
+
+    buffer[0] = 0xf1;
+    buffer[1] = 0x01;
+    buffer[2] = dwMode;
+    buffer[3] = dwTol1;
+    buffer[4] = dwTol2;
+    buffer[5] = dwLevel1;
+    buffer[6] = dwLevel1>>8;
+    buffer[7] = dwLevel2;
+    buffer[8] = dwLevel2>>8;
+    buffer[9] = dwRepeat1;
+    buffer[10] = dwRepeat2;
+
+    if ((write(device, buffer, 11, 500)) != 11 || (read(device, buffer, 1, 500)) != 1 || buffer[0] != 0x01) {
+        fprintf(stderr, "SetFtDistanceSensorMode: Error communicating with serial\n");
+        return buffer[0];
+    }
+    usleep(100000); // wait before continue, else it doesn't always work
+    return FTLIB_ERR_SUCCESS;
+}
+
+unsigned ftcommdev::pgm_message(unsigned code, unsigned dwMemBlock) {
+    unsigned char buffer[2];
+    if (type != FT_ROBO_IF_COM) return FTLIB_ERR_NOT_SUPPORTED;
+    buffer[0] = code;
+    buffer[1] = dwMemBlock;
+    if ((write(device, buffer, 2, 500)) != 2 || (read(device, buffer, 1, 500)) != 1) {
+        return FTLIB_ERR_IF_NO_PROGRAM;
+    }
+    if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS;
+    else return FTLIB_ERR_IF_NO_PROGRAM;
+}
+