class library to access fischertechnik interfaces via USB

Dependencies:   FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp

ftlib/ftlibclasstxc.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 "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);
}