class library to access fischertechnik interfaces via USB
Dependencies: FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp
Diff: ftlib/ftlibclasstxc.cpp
- 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); +} +