class library to access fischertechnik interfaces via USB
Dependencies: FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp
ftlib/ftlibclassusb.cpp
- Committer:
- networker
- Date:
- 2013-03-11
- Revision:
- 1:4676e8b9b357
- Parent:
- 0:7da612835693
File content as of revision 1:4676e8b9b357:
#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; }