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/ftlibclasstxc.cpp	Wed Jun 15 19:12:25 2011 +0000
@@ -0,0 +1,501 @@
+#include "mbed.h"
+#include "USBHost.h"
+#include "ftlibclasstxc.h"
+#include "ftErrCode.h"
+
+ftusbdevtx::ftusbdevtx(): ftusbdev(0, FT_TXC, 0) {
+    sid = 0;
+    tid = 0;
+    active = 0;
+    transferAktiv = FTX1STOP;
+    cbRoboExtState = 0;
+    for (int i = TA_LOCAL; i <  TA_N_PARTS; i++)  ta[i] = 0;
+}
+
+ftusbdevtx::ftusbdevtx(int d): ftusbdev(d, FT_TXC, 0) {
+    sid = 0;
+    tid = 0;
+    active = 0;
+    transferAktiv = FTX1STOP;
+    cbRoboExtState = 0;
+    for (int i = TA_LOCAL; i <  TA_N_PARTS; i++)  ta[i] = 0;
+    set_baudrate(38400);
+    send_msg(1); //ping
+    GetFtSerialNr();
+}
+
+void ftusbdevtx::getSlaveInfo() {
+    send_msg(7, 1); //get state for master
+    for (int i = 1; i <= N_EXT_DEV; i++)
+        if (ta[0]->state.ext_dev_connect_state[i-1]) {
+            if (ta[i] == 0) { //new slave
+                ta[i] = new TA;
+                memset(ta[i], 0, sizeof(TA));
+                active |= 1<<i;
+                send_msg(6, 1<<i); //get info for slave;
+                printf("New Extension %d = %s\n", i, ta[i]->info.device_name);
+                if (cbRoboExtState) cbRoboExtState(i, 1);
+            }
+        } else {
+            if (ta[i]) {
+                delete ta[i];
+                ta[i] = 0;
+                active &= ~(1<<i);
+                printf("Extension %d went offline\n", i);
+                if (cbRoboExtState) cbRoboExtState(i, 0);
+            }
+        }
+//    send_msg(6, active & ~1); //get info for slaves;
+}
+
+unsigned ftusbdevtx::OpenFtUsbDevice() {
+    ta[0] = new TA;
+    memset(ta[0], 0, sizeof(TA));
+    active = 1;
+    send_msg(6, 1); //get info for master
+    printf("Master=%s\n", ta[0]->info.device_name);
+    getSlaveInfo(); /*
+    send_msg(7, 1); //get state for master
+    for (int i = 0; i < N_EXT_DEV; i++)
+        if (ta[0]->state.ext_dev_connect_state[i]) {
+            ta[i+1] = new TA;
+            memset(ta[i+1], 0, sizeof(TA));
+            active |= 1<<(i+1);
+            send_msg(6, 1<<(i+1)); //get info for slave;
+            printf("Extension %d = %s\n", i+1, ta[i+1]->info.device_name);
+        }*/
+//    send_msg(6, active & ~1); //get info for slaves;
+    return 0;
+}
+
+unsigned ftusbdevtx::CloseFtDevice() {
+    if (ta[0]==0)
+        return FTLIB_ERR_DEVICE_NOT_OPEN;
+    while (transferAktiv != FTX1STOP) {
+        fprintf(stderr, "Transfer ta still active\n");
+        wait(1);
+    }
+    for (int i = 0; i < N_EXT_DEV; i++)
+        if (ta[i]!=0) {
+            delete ta[i];
+            ta[i] = 0;
+        }
+    return 0;
+}
+
+unsigned ftusbdevtx::IsFtTransferActiv() {
+    if (ta[0] == 0)
+        return FTLIB_ERR_DEVICE_NOT_OPEN;//or just say not running
+    if (transferAktiv == FTX1RUN)
+        return FTLIB_ERR_THREAD_IS_RUNNING;
+    if (transferAktiv == FTX1STOP)
+        return FTLIB_ERR_THREAD_NOT_RUNNING;
+    return FTLIB_ERR_THREAD_SYNCHRONIZED;
+}
+
+
+unsigned ftusbdevtx::set_baudrate(unsigned br) {
+    unsigned char buffer[7] = {0x00, 0x96, 0x00, 0x00, 0, 0, 8};
+    *(unsigned*)buffer = br;
+    int ret = USBControlTransfer(device, 0x21, 0x20, 0, 0, buffer, 7);
+    if (ret != 7)
+        printf("error setting Baudrate: %d\n", ret);
+    ret = USBControlTransfer(device, 0xa1, 0x21, 0, 0, buffer, 7);
+    if (ret == 7)
+        printf("baudrate=%d, format=%d, parity=%d, bits=%d\n", *(int*)buffer, buffer[4], buffer[5], buffer[6]);
+    else
+        printf("error getting Baudrate: %d\n", ret);
+    return *(unsigned*)buffer;
+}
+
+unsigned ftusbdevtx::GetFtSerialNr() {
+    if (sn) return sn;
+    unsigned char req_sn[] = "\x0dget_ser_num\x0d";
+    char ser[80];
+    memset(ser, 0, sizeof(ser));
+    int ret=write_data(req_sn, sizeof(req_sn)-1);
+    if (ret != sizeof(req_sn)-1)
+        printf("bulk write error: %d\n", ret);
+    ret=read_data((unsigned char*)ser, sizeof(ser));
+    if (ret < 0)
+        printf("bulk read error: %d\n", ret);
+    char s1[41],s3[31];
+    unsigned num=0;
+    int n = sscanf(ser,"\x0d\x0a%40[^\n\r]%u\x0d\x0a%30[^\n\r]", s1, &num, s3);
+    if (n==3) {
+        sn = num;
+        printf("%010u  %s\n",  num, s3);
+    } else
+        printf("could not parse serial number [%s]\n", ser);
+    return sn;
+}
+
+char* ftusbdevtx::GetFtLongNameStrg() {
+    unsigned char req_sn[] = "\x0dget_ser_num\x0d";
+    char ser[80];
+    memset(ser, 0, sizeof(ser));
+    int ret=write_data(req_sn, sizeof(req_sn)-1);
+    if (ret != sizeof(req_sn)-1)
+        printf("bulk write error: %d\n", ret);
+    ret=read_data((unsigned char*)ser, sizeof(ser));
+    if (ret < 0)
+        printf("bulk read error: %d\n", ret);
+    char s1[41],s3[31]="";
+    unsigned num=0;
+    int n = sscanf(ser,"\x0d\x0a%40[^\n\r]%u\x0d\x0a%30[^\n\r]", s1, &num, s3);
+    return strdup(s3);
+}
+
+TA*  ftusbdevtx::GetFtTransferAreaAddress(int i) {
+    if (i < N_EXT_DEV)
+        if (ta[i])
+            return ta[i];
+        else
+            printf("TX%d is not open\n", i);
+    else
+        printf("Index out of range (%d)\n", i);
+    return 0;
+}
+
+unsigned ftusbdevtx::StartFtTransferArea(NOTIFICATION_EVENTS* ev) {
+    int err = IsFtTransferActiv();
+    if (err == FTLIB_ERR_THREAD_IS_RUNNING)
+        return err;
+    if (active==0)
+        return FTLIB_ERR_DEVICE_NOT_OPEN;
+    if (ev)
+        ne = *ev; //copy the entire struct
+    else
+        memset(&ne, 0, sizeof(NOTIFICATION_EVENTS));
+    FtThreadInit(); //sets busy to false
+    transferAktiv = FTX1RUN;//indicate that thread is running
+    return FTLIB_ERR_SUCCESS;
+}
+
+void ftusbdevtx::FtThreadBegin() {
+    if (!test_and_set()) {//return when transferarea is in use
+        busy = false; //release the mutex, otherwise the thread effectively stops
+        printf("TA busy: skip begin slot\n");
+        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
+    }
+    transferAktiv = FTX1SYNC;//indicate that TA is being updated (like busy)
+    send_msg(2, active, false);
+    increment();
+}
+
+void ftusbdevtx::FtThreadEnd() {
+    if (!test_and_set()) {//skip when busy
+        busy = false;
+        printf("TA busy: skip end slot\n");
+        return;
+    }
+    rec_msg(); //parse the message
+    increment(); //release the TA mutex
+    if (ne.NotificationCallback) {
+        ne.NotificationCallback(ne.Context);
+    }
+    if (tid%100 == 0) { //about every 1 seconds
+        //getSlaveInfo(); //synchronous! TODO: change to non-blocking
+    }
+    transferAktiv = FTX1RUN;//TA update complete
+    busy = false;  //ready for the next tick
+//    printf("Busy released\n");
+}
+
+UINT16 ftusbdevtx::checksum(unsigned char *p, unsigned n) {
+    UINT16 sum = 0;
+    do {
+        sum -= *p++;
+    } while (--n);
+    return (sum<<8)|(sum>>8);
+}
+
+void ftusbdevtx::dump_buffer(int size) {
+    if (buffer==0) {
+        printf("No buffer\n");
+        return;
+    }
+    for (int i = 0; i < size; i++) {
+        printf("%02X ", buffer[i]);
+        if (i%16 == 15) printf("\n");
+    }
+    printf("----------------------\n");
+}
+
+unsigned ftusbdevtx::send_msg(unsigned cmd, unsigned set, bool sync) {
+    const unsigned sizes[] = {0, 0, //cmd 1
+                              sizeof(TA_OUTPUT)+sizeof(UINT32), //cmd 2
+                              0, //unknown
+                              0, //unknown
+                              sizeof(TA_CONFIG)+sizeof(UINT32), //cmd 5
+                              sizeof(UINT32), //cmd 6
+                              sizeof(UINT32), //cmd 7
+                              sizeof(DISPLAY_MSG)+sizeof(UINT32), //cmd 8
+                              DEV_NAME_LEN + 1+3 + sizeof(UINT32) //cmd 9
+                             };
+    int ret = 0;
+    int n = 0;
+    for (int i = TA_LOCAL; i < TA_N_PARTS; i++) {
+        if (set & (1<<i)) {
+            n++;
+        }
+    }
+    unsigned size = 0;
+    if (cmd < sizeof(sizes)/sizeof(unsigned))
+        size = sizes[cmd];
+    unsigned payload_size = n*size;
+    num_read = sizeof(header)+sizeof(trailer);
+    unsigned total_size = sizeof(header)+payload_size+sizeof(trailer);
+    buffer = new unsigned char[total_size]; //size must be known in advance
+
+    unsigned net_size = total_size-sizeof(UINT32)-sizeof(trailer);//exclude start,len,crc,etx
+    header *hdr = (header*)buffer;
+    hdr->start = 0x5502;
+    hdr->bytesH = net_size>>8;
+    hdr->bytesL = net_size&0xff;
+    hdr->body.snd = 2;
+    hdr->body.rec = 1;
+    hdr->body.trans = ++tid;
+    hdr->body.session = sid;
+    hdr->body.cmd = cmd;
+    hdr->body.structs = n;
+    unsigned char* payload = buffer+sizeof(header);
+    for (int i = TA_LOCAL; i < TA_N_PARTS; i++) {
+        if (ta[i]==0 || !(set & (1<<i))) {
+            if (set & (1<<i)) printf("TX %d is not open yet!\n", i);
+            continue;
+        }
+        unsigned *id = (unsigned*)payload;
+        *id = i;
+        payload = (unsigned char*)(id+1);
+        num_read += sizeof(UINT32);
+        switch (cmd) {
+            case 1:
+                break;
+            case 2:
+                memcpy(payload, &ta[i]->output, sizeof(TA_OUTPUT));
+                payload += sizeof(TA_OUTPUT);
+                num_read += sizeof(TA_INPUT);
+                break;
+            case 5:
+                memcpy(payload, &ta[i]->config, sizeof(TA_CONFIG));
+                payload += sizeof(TA_OUTPUT);
+                break;
+            case 6:
+                num_read += sizeof(TA_INFO);
+                break;
+            case 7:
+                num_read += sizeof(TA_STATE);
+                break;
+            case 8:
+                memcpy(payload, &ta[i]->display.display_msg, sizeof(DISPLAY_MSG));
+                payload += sizeof(DISPLAY_MSG);
+                break;
+            case 9:
+                memcpy(payload, ta[i]->info.device_name, DEV_NAME_LEN + 1+3);
+                payload += sizeof(DEV_NAME_LEN + 1+3);
+                break;
+            default:
+                printf("Unknown message type %d\n", cmd);
+                break;
+        }
+    }
+    trailer *trl = (trailer*)payload;
+    trl->chksum = checksum(buffer+2, net_size+2);
+    trl->etx = '\x03';
+    num_read--;
+    //dump_buffer(total_size);
+    //printf("Expecting %d bytes for transaction %d\n", num_read, tid);
+    if (sync) {
+        ret = write_data(buffer, total_size-1);//send 1 less because trailer is 1 too long due to alignment
+        delete[] buffer;
+        if (ret < 0)
+            printf("synchronous send_message failed (%d)\n", ret);
+        else {
+            buffer = new unsigned char[num_read];
+            ret = read_data(buffer, num_read);
+            if (ret < 0) {
+                printf("synchronous read failed (%d)\n", ret);
+                delete[] buffer;
+            } else {
+                //dump_buffer(num_read);
+                rec_msg();
+            }
+        }
+    } else
+        write_data(buffer, total_size-1, &ftusbdevtx::write_finished_cb, this);
+    return ret;
+}
+#if 0
+unsigned ftusbdevtx::rec_msg() {
+    header *hdr = (header*)buffer;
+    //dump_buffer(num_read);
+    if (hdr->start != 0x5502) printf("Invalid packet\n");
+    unsigned net_size = (hdr->bytesH<<8) + hdr->bytesL;
+    if (net_size+7 != num_read) printf("message has %d bytes, was expecting %d bytes\n", net_size+7, num_read);
+    //printf("message %d from %d\n", hdr->cmd, hdr->snd);
+    if (hdr->rec != 2) printf("Wrong destination (%d)\n", hdr->rec);
+    if (hdr->trans != tid) printf("Response to request %d, expected %d\n", hdr->trans, tid);
+    if (hdr->session != sid) {
+        printf("Session number has changed from %d to %d\n", sid, hdr->session);
+        sid = hdr->session;
+        tid = 1; //restart transaction sequence
+    }
+    unsigned cmd = hdr->cmd - 100;
+    unsigned n = hdr->structs;
+    unsigned char* payload = buffer+sizeof(header);
+    trailer *trl = (trailer*)(buffer+net_size+4);
+    for (int i = 0; i < n && payload < (unsigned char*)trl; i++) {
+        unsigned *id = (unsigned*)payload;
+        if (*id >= TA_N_PARTS) {
+            printf("Illegal extension nr %d\n", *id);
+            continue;
+        }
+        if (ta[*id]==0) {
+            printf("Message for new device %d\n", *id);
+            continue;//skip the copy to avoid assignment to null ta but the payload pointer is not advanced! stopping further copying
+        }
+        payload = (unsigned char*)(id+1);
+        switch (cmd) {
+            case 1:
+                break;
+            case 2:
+                memcpy(&ta[*id]->input, payload, sizeof(TA_INPUT));
+                payload += sizeof(TA_INPUT);
+                break;
+            case 5:
+                break;
+            case 6:
+                memcpy(&ta[*id]->info, payload, sizeof(TA_INFO));
+                payload += sizeof(TA_INFO);
+                break;
+            case 7:
+                memcpy(&ta[*id]->state, payload, sizeof(TA_STATE));
+                payload += sizeof(TA_STATE);
+                break;
+            case 8:
+                break;
+            case 9:
+                break;
+            default:
+                printf("Unknown message type %d\n", cmd);
+                break;
+        }
+    }
+    if (payload != (unsigned char*)trl) printf("expected %d sections with in total %d bytes; got %d bytes\n", n, payload-buffer-sizeof(header), net_size-sizeof(header));
+    if (trl->chksum != checksum(buffer+2, net_size+2)) printf("Checksum error\n");
+    if (trl->etx != '\x03') printf("Expected ETX(03), got %02X\n", trl->etx);
+    delete[] buffer;
+    return 0;
+}
+#else
+unsigned ftusbdevtx::rec_msg() {
+    header *hdr = (header*)buffer;
+    //dump_buffer(num_read);
+    if (hdr->start != 0x5502) printf("Invalid packet\n");
+    unsigned net_size = (hdr->bytesH<<8) + hdr->bytesL;
+    if (net_size+7 != num_read) printf("message has %d bytes, was expecting %d bytes\n", net_size+7, num_read);
+    rec_msg2(&hdr->body, net_size);
+    trailer *trl = (trailer*)(buffer+net_size+4);
+    if (trl->chksum != checksum(buffer+2, net_size+2)) printf("Checksum error\n");
+    if (trl->etx != '\x03') printf("Expected ETX(03), got %02X\n", trl->etx);
+    delete[] buffer;
+    return 0;
+}
+
+unsigned ftusbdevtx::rec_msg2(headerbody *hdr, unsigned net_size) {
+    //printf("message %d from %d\n", hdr->cmd, hdr->snd);
+    if (hdr->rec != 2) printf("Wrong destination (%d)\n", hdr->rec);
+    if (hdr->trans != tid) printf("Response to request %d, expected %d\n", hdr->trans, tid);
+    if (hdr->session != sid) {
+        printf("Session number has changed from %d to %d\n", sid, hdr->session);
+        sid = hdr->session;
+        tid = 1; //restart transaction sequence
+    }
+    unsigned cmd = hdr->cmd - 100;
+    unsigned n = hdr->structs;
+    if (n==0)
+        printf("Got reply to cmd %d\n", cmd);
+    unsigned char* payload = (unsigned char *)(hdr+1);
+    unsigned char* trl = (unsigned char*)hdr+net_size;
+    for (int i = 0; i < n && payload < trl; i++) {
+        unsigned *id = (unsigned*)payload;
+        if (*id >= TA_N_PARTS) {
+            printf("Illegal extension nr %d\n", *id);
+            continue;
+        }
+        if (ta[*id]==0) {
+            printf("Message for new device %d\n", *id);
+            continue;//skip the copy to avoid assignment to null ta but the payload pointer is not advanced! stopping further copying
+        }
+        payload = (unsigned char*)(id+1);
+        switch (cmd) {
+            case 1:
+                break;
+            case 2:
+                memcpy(&ta[*id]->input, payload, sizeof(TA_INPUT));
+                payload += sizeof(TA_INPUT);
+                break;
+            case 5:
+                break;
+            case 6:
+                memcpy(&ta[*id]->info, payload, sizeof(TA_INFO));
+                payload += sizeof(TA_INFO);
+                break;
+            case 7:
+                memcpy(&ta[*id]->state, payload, sizeof(TA_STATE));
+                payload += sizeof(TA_STATE);
+                if (*id == 0)
+                    for (int i = 1; i <= N_EXT_DEV; i++)
+                        if (ta[0]->state.ext_dev_connect_state[i-1]) {
+                            if (!(active & (1<<i))) { //new slave
+                                active |= 1<<i;
+                                if (ta[i] == 0) { //new slave
+                                    ta[i] = new TA;
+                                    memset(ta[i], 0, sizeof(TA));
+                                }
+                                send_msg(6, 1<<i, false); //get info for slave;
+                                printf("New Extension %d = %s\n", i, ta[i]->info.device_name);
+                                if (cbRoboExtState) cbRoboExtState(i, 1);
+                            }
+                        } else {
+                            if (active & (1<<i)) {
+                                active &= ~(1<<i);
+                                printf("Extension %d went offline\n", i);
+                                if (cbRoboExtState) cbRoboExtState(i, 0);
+                            }
+                        }
+
+                break;
+            case 8:
+                break;
+            case 9:
+                break;
+            default:
+                printf("Unknown message type %d\n", cmd);
+                break;
+        }
+    }
+    if (payload != trl)
+        printf("expected %d sections with in total %d bytes; got %d bytes\n", n, payload-(unsigned char*)(hdr+1), net_size-sizeof(headerbody));
+    return cmd;
+}
+#endif
+void ftusbdevtx::read_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) {
+//end of reply transfer
+//printf("read_finished_cb: %d bytes\n", len);
+    ftusbdevtx *fth = (ftusbdevtx*)userData;
+    if (fth->transferAktiv == FTX1SYNC)
+        fth->FtThreadEnd();
+    else
+        fth->rec_msg();
+}
+
+void ftusbdevtx::write_finished_cb(int device, int endpoint, int status, u8* data, int len, void* userData) { //end of request transfer, issue, reply transfer
+    ftusbdevtx *fth = (ftusbdevtx*)userData;
+//printf("write_finished_cb: wrote %d bytes, reading %d bytes\n", len, fth->num_read);
+    delete[] fth->buffer;
+    fth->buffer = new unsigned char[fth->num_read];
+    USBInterruptTransfer(fth->device, 0x82, fth->buffer, fth->num_read, read_finished_cb, fth);
+}
+