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