Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.
libft.c
- Committer:
- networker
- Date:
- 2011-05-04
- Revision:
- 1:2c9d412ad471
- Parent:
- 0:7f26f0680202
File content as of revision 1:2c9d412ad471:
//this file was adapted by Ad for use in the mbed environment //currently all USB functionality has been disabled, this may change in the future //the comport functionality has been adapted to the mbed serial class //threads and semphores were replaced by other primitives //as a consequence also the ftlib.h was adapted /** @file * * Copyright (C) 2007 Erik Andresen erik@vontaene.de * * Open Source version of the fischertechnik ROBO Interface Library for Unix like systems * * Communication is done through a "transfer area" this is constantly updated. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * \example example.c * * \mainpage libft Index Page * * \section intro_sec Introduction * * libft is an Open Source version of the fischertechnik ROBO Interface Library for Unix like systems * * The goal is to create a library that is fully compatible with the ftlib by knobloch eletronic. * * This library should work on any systems supported by libusb, like Linux, BSD and Mac OS X and is released * under the GNU Lesser General Public License (LGPL) * * Included is the helper program "ftuploader" which allows you to upload programs to the Robo Interface.\n * Running ftuploader --help should give you an idea how to use it.\n * Also included is an Interface Diagnose utility. See section Interface Diagnose * * \section dl_sec Download * Current Version: 0.4.3 * * See http://defiant.homedns.org/~erik/ft/libft/files/ \n * Download Latest version: http://defiant.homedns.org/~erik/ft/libft/files/libft-current.tar.gz * * \section req_sec Requirements * - libusb - http://libusb.sourceforge.net/ * - cmake at least version 2.4 - http://cmake.org * - pthreads (Should be included with every modern posix compatible OS) * * * \section apidoc_sec API Documentation * \see libft.c * * \section install_sec Installation * * \subsection step1 Step 1: Compiling * * Type * - cmake . * - make * \subsection step2 Step 2: Installation * Type * - make install * * After installing you should run * - ldconfig * * to make the library known to your system. Make sure that /etc/ld.so.conf is configured to include /usr/local/li * * To install the diagnose utility type * - make diag * * Debian packages are available. Please read http://vontaene.de/apt/README.txt.\n * You can install them with apt-get install libft0 libft-doc libft-python libft-diag * * \subsection step3 Step 3: udev * When running udev you might want to copy the file fischertechnik.rules from the udev folder to /etc/udev/rules.d/ to get the correct permissions.\n * Udev then needs a reload with * - udevcontrol reload_rules * * You will now need to replug your device. * * \subsection step4 Step 4: Create Documentation\n * Type\n * - make doc\n * to create the html API documentation. * * \subsection step5 Step 5: Python * A Python interface to this library is available, see the python folder for details.\n * Type\n * make python\n * * in the python/ -folder to install the python module. * Use pydoc to read its documentation: * - pydoc robointerface in the shell * - help(robointerface) from the python interpreter * * \section diag_sec Interface Diagnose * You can find it in the folder diag/.\n * It requires the python module (see above) and PyQT4. You can launch it by running "sh ftdiagnose" * \image html diag1.png * * \section author_sec Author * Erik Andresen - erik@vontaene.de * * Please contact me for bugs or any suggestions * * Homepage of libft: http://defiant.homedns.org/~erik/ft/libft/ * * * \section changes_sec Changes * * - 0.4.3: - Bug fix: Extension digital inputs at RoboRF * - ftdiagnose: Display connection status * - Added functions: (not in Knobloch lib): * - IsFtInterfaceConnected() * - Python added functions: * - IsConnected() * - 0.4.2: - Python support to open the interface by serial * - Some Bug fixes * - Added functions: (not in Knobloch lib) * - SetRealSerial() * - 0.4.1: * - Added support to change the RF address. * - Added functions: (not in Knobloch lib) * - SetRFMode() * - GetRFMode() * - Added support for functions: * - GetFtManufacturerStrg() * - GetFtShortNameStrg() * - GetFtLongNameStrg() * - GetFtLibErrorString() * - Some minor Bug fixes * - 0.4: * - Hopefully support for more then one Robo Interface attached to an RF Link. * - InitFtUsbDeviceList() will now also count the number of Robo Interfaces attached to an RF Link * - Added support for the ft distance sensor * - Added functions: * - GetFtDeviceTypeString() (not in Knobloch lib) * - Added support for functions: * - SetFtDistanceSensorMode() * - Python added functions: * - GetNumFtUsbDevices() * - RoboInterface.GetDeviceTypeString() * - GetD1() * - GetD2() * - Added ft Diagnose utility. * - 0.3: * - added (overwrite) --target option to the ftuploader * - included some documentation * - minor fixes * - enhanced python layer * - support for RF Module * - 0.2.1: * - fixed Analog/Voltage Sensor calculations * - 0.2: * - added udev file * - experimental support for uploading to the interface (usb only) * - included program ftuploader * - add support for functions: * - DownloadFtProgram() * - StartFtProgram() * - StopFtProgram() * - DeleteFtProgram() * - SetFtProgramActiv() * - GetFtProgramName() * - GetFtStatus() * - GetFtFirmware() * - GetFtFirmwareStrg() * - GetFtSerialNr() * - GetFtSerialNrStrg() * * * \section porting_sec Porting your program from the Knobloch Windows Library * When porting your program from the Knobloch Library for Microsoft Windows operation systems please note the following: * - The name of this library is libft, not ftlib (the Knobloch original) to follow the UNIX naming scheme * - Types like DWORD are replaced with their logical ANSI-C counterparts, like * -# DWORD - long int * -# LPCSTR - char * * -# LPVOID - void * * -# BYTE - unsigned char * -# USHORT - unsigned short int * -# UINT - unsigned int * -# UCHAR - unsigned char * - The Windows Notifications stuff will probably never be supported. * - Some return codes might be different, so if something is going wrong, check this manual. * */ #define MBED #define NOTNOW #define SPLITTRANSFER #ifdef MBED #include "mbed.h" #define usleep(x) wait_us(x) #define sleep(x) wait(x) #define LIBFT_VERSION_MAJOR 1 #define LIBFT_VERSION_MINOR 0 #define LIBFT_VERSION_PATCH 0 Serial viaUsb(USBTX, USBRX); #else #include <stdio.h> #include <string.h> #include <pthread.h> #include <semaphore.h> #include <termios.h> #include <fcntl.h> #endif #ifdef USE_USB #include <usb.h> #else //some dummy USB stuff #endif #ifdef USE_DOWNLOAD #include "crc.h" #endif #include "ftlib.h" /** \cond doxygen ignore start */ #define VERSION_MAJOR LIBFT_VERSION_MAJOR #define VERSION_MINOR LIBFT_VERSION_MINOR #define VERSION_PATCH LIBFT_VERSION_PATCH #define FT_VENDOR_ID 0x146a #define ROBO_IF_PRODUCT_ID 0x1 #define EXT_IF_PRODUCT_ID 0x2 #define RF_DATA_LINK_PRODUCT_ID 0x3 #define ABF_IF_COMPLETE 0x8b // 0xf2 #define INTERFACE_QUERY_TIME 10000 // �s == 5ms #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 #ifdef MBED #define BAUDRATE_II 9600 #define BAUDRATE_RI 38400 #else #define BAUDRATE_II B9600 #define BAUDRATE_RI B38400 #endif #define PROGRAM_UPLOAD_PACKET_SIZE 128 #ifndef MIN #define MIN(a, b) ( (a)<=(b) ? (a) : (b) ) #endif /** \endcond doxygen ignore end */ /** * \brief Returns lib version * * Returns the library version. * * @return version as Major Minor Patch */ long int GetLibVersion() { return VERSION_MAJOR<<16 | VERSION_MINOR<<8 | VERSION_PATCH; } /** * \brief Returns lib version * * Returns the library version. * The allocated space should be freed with free() later. * * @return Pointer to a string with the serial */ char *GetLibVersionStrg() { long int ver = GetLibVersion(); char *s = (char *)malloc(16); int byte1 = ver & 0xff; int byte2 = (ver & 0xff00) >> 8; int byte3 = (ver & 0xff0000) >> 16; snprintf(s, 16, "%d.%02d.%02d", byte3, byte2, byte1); return s; } /** * \brief Library initialization (dummy) * * Dummy for compatibility. Only used in original library. * @return Always FTLIB_ERR_SUCCESS */ long int InitFtLib() { return FTLIB_ERR_SUCCESS; } /** * \brief Initiates and scans the USB bus * * This function has to be called before any other USB action. * It will set up USB basic variables and then scan the USB bus. * * @return Always FTLIB_ERR_SUCCESS. Not able to fail. */ long int InitFtUsbDeviceList() { #ifdef USE_USB usb_init(); usb_find_busses(); usb_find_devices(); #endif return FTLIB_ERR_SUCCESS; } /** \cond doxygen ignore start */ static unsigned int GetNumFtDevicesFromRF(struct usb_device *dev) { unsigned int iNum = 0; #ifdef USE_USB usb_dev_handle *device; int ret; unsigned char buffer[35] = { 0 }; int i; device = usb_open(dev); for (i=1; i<9; i++) { ret = usb_control_msg(device, 0xc0, 0x52, i<<8 | 0x05, 0, buffer, 35, FT_USB_TIMEOUT); if (ret < 0) fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); else if (buffer[0] == 0xfa && buffer[1] == 0) iNum++; // buffer[1] == 0xff => no device } usb_close(device); #endif return iNum; } static unsigned int GetNthFtDeviceFromRF(struct usb_device *dev, int iNum) { int ret=0; #ifdef USE_USB usb_dev_handle *device; unsigned char buffer[35] = { 0 }; int i; device = usb_open(dev); for (i=1; i<9, iNum>0; i++) { ret = usb_control_msg(device, 0xc0, 0x52, i<<8 | 0x05, 0, buffer, 35, FT_USB_TIMEOUT); if (ret < 0) fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); else if (buffer[0] == 0xfa && buffer[1] == 0) iNum--; // buffer[1] == 0xff => no device ret = i; } usb_close(device); #endif return ret; } static int GetFtDeviceFromRFWithSerial(struct usb_device *dev, long int dwSN) { #ifdef USE_USB usb_dev_handle *device; int ret; unsigned char buffer[35] = { 0 }; int i; long int serial; device = usb_open(dev); for (i=1; i<9; i++) { ret = usb_control_msg(device, 0xc0, 0x52, i<<8 | 0x05, 0, buffer, 35, FT_USB_TIMEOUT); if (ret < 0) fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); else if (buffer[0] == 0xfa && buffer[1] == 0) { // buffer[1] == 0xff => no device serial = buffer[6]<<24 | buffer[5]<<16 | buffer[4]<<8 | buffer[3]; if (serial == dwSN) { return i; } } } usb_close(device); #endif return 0; } /** \endcond doxygen ignore end */ /** * \brief Get the count of found ft Interfaces over USB. * * If we find a Robo RF Data Link we will count the devices attached to it instead * * @return Number of ft Interface devices on the USB bus found. */ unsigned int GetNumFtUsbDevice() { unsigned int iNum = 0; #ifdef USE_USB struct usb_device *dev; struct usb_bus *busses; struct usb_bus *bus; busses = usb_get_busses(); for (bus = busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == FT_VENDOR_ID) { if (dev->descriptor.idProduct == RF_DATA_LINK_PRODUCT_ID) { iNum+=GetNumFtDevicesFromRF(dev); } iNum++; } } } #endif return iNum; } /** \cond doxygen ignore start */ static int FtproductIDToInterfaceID(int iProductID) { switch (iProductID) { case ROBO_IF_PRODUCT_ID: return FT_ROBO_IF_USB; case EXT_IF_PRODUCT_ID: return FT_ROBO_IO_EXTENSION; case RF_DATA_LINK_PRODUCT_ID: return FT_ROBO_RF_DATA_LINK; } return 0; } static int FtInterfaceIDToProductID(int InterfaceID) { switch (InterfaceID) { case FT_ROBO_IF_USB: return ROBO_IF_PRODUCT_ID; case FT_ROBO_IO_EXTENSION: return EXT_IF_PRODUCT_ID; case FT_ROBO_RF_DATA_LINK: return RF_DATA_LINK_PRODUCT_ID; } return 0; } /** \endcond doxygen ignore end */ /** * \brief Gets the handle to a ft USB device. * * Get the handle for the ft USB device with this number. * Passing just 0 as argument will use the first device found. * * Count the interfaces with GetNumFtUsbDevice() * * @see GetNumFtUsbDevice() * @param Num selected Interface. If unsure try 0. * @return The ft device or NULL if error */ FT_HANDLE GetFtUsbDeviceHandle(unsigned char Num) { #ifdef USE_USB struct usb_device *dev; struct usb_bus *busses; struct usb_bus *bus; int i=0; FT_HANDLE ret; int count_ri_at_rf; busses = usb_get_busses(); for (bus = busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == FT_VENDOR_ID) { if (dev->descriptor.idProduct == RF_DATA_LINK_PRODUCT_ID) { count_ri_at_rf = GetNumFtDevicesFromRF(dev); i+=count_ri_at_rf; } if (i >= Num) { // '>=' because any RF will add more then 1 to the count ret = (FT_HANDLE) malloc (sizeof(struct ft_handle_devices)); if (ret == NULL) { perror("GetFtUsbDeviceHandle malloc"); return NULL; } ret->device = NULL; ret->dev = dev; ret->sdev = 0; ret->type = FtproductIDToInterfaceID(dev->descriptor.idProduct); sem_init(&ret->lock, 0, 1); memset(&ret->transfer_area, 0, sizeof(struct _FT_TRANSFER_AREA)); ret->transfer_area.TransferAktiv = 0; ret->query_time = INTERFACE_QUERY_TIME; ret->transfer_area.RfModulNr = -1; ret->interface_connected = 0; if (dev->descriptor.idProduct == RF_DATA_LINK_PRODUCT_ID) { ret->transfer_area.RfModulNr = GetNthFtDeviceFromRF(dev, Num); if (ret->transfer_area.RfModulNr == 0) // user has chosen the RF Modul, so choose the first Interface at RF for the user ret->transfer_area.RfModulNr = GetNthFtDeviceFromRF(dev, 1); else ret->type = FT_ROBO_IF_OVER_RF; } return ret; } i++; } } } #endif return NULL; } /** * \brief Gets the handle to a ft USB device with a specific serial number. * * Get the handle for the ft USB device with this number. * Serial is 1 for most devices, unless explicitly changed in the device. * Second argument can be FT_AUTO_TYPE. * * @param dwSN Serial of the USB Device * @param dwTyp Type of the USB Device: FT_AUTO_TYPE, FT_ROBO_IF_USB, FT_ROBO_IO_EXTENSION, FT_ROBO_IF_OVER_RF or FT_ROBO_RF_DATA_LINK * @return The ft device or NULL on error */ FT_HANDLE GetFtUsbDeviceHandleSerialNr(long int dwSN, long int dwTyp) { #ifdef USE_USB int i; FT_HANDLE ret; for (i=0; i < GetNumFtUsbDevice(); i++) { ret = GetFtUsbDeviceHandle(i); OpenFtUsbDevice(ret); if ((dwTyp == FT_AUTO_TYPE || ret->type == dwTyp) && GetFtSerialNr(ret) == dwSN) { CloseFtDevice(ret); return ret; } CloseFtDevice(ret); } #endif return NULL; } //blocking int read(Serial *d, unsigned char *ptr, int n) { for (int i = 0; i< n; i++) { ptr[i] = d->getc(); } return n; } int read(Serial *stream, unsigned char *buf, int n, int timeout_ms) { Timer t; t.start(); int i = 0; while (t.read_ms() < timeout_ms && i < n) { if (stream->readable()) buf[i++] = stream->getc(); } return i; } //blocking int write(Serial *d, unsigned char *ptr, int n) { for (int i = 0; i< n; i++) { d->putc(ptr[i]); } return n; } int write(Serial *d, unsigned char *ptr, int n, int timeout_ms) { Timer t; t.start(); int i = 0; while (t.read_ms() < timeout_ms && i < n) { if (d->writeable()) d->putc(ptr[i++]); } return i; } //non-blocking int ft_handle_devices::write() { windex = 0; //sdev->attach(this, &ft_handle_devices::writeByte, Serial::TxIrq);//could be moved to FtThreadInit //sdev->attach(this, &ft_handle_devices::readByte, Serial::RxIrq); writeByte(); //write the first byte, callback will take care of the rest return num_write; } void ft_handle_devices::writeByte() { if (windex < num_write) { sdev->putc(out[windex++]); if (windex == num_write) rindex = 0; } } void ft_handle_devices::readByte() { if (rindex < num_read) { in[rindex++] = sdev->getc(); if (rindex == num_read) { //sdev->attach(0,Serial::RxIrq);//could be moved to FtThreadFinish //sdev->attach(0,Serial::TxIrq); FtThreadEnd(); } } } /** * \brief Gets the handle to a ft serial device. * * Get the handle for the ft Serial device at the selected serial port. * * @param sDevice filename of your serial device, like /dev/ttyS0. * @param dwTyp Interface type. FT_INTELLIGENT_IF, FT_INTELLIGENT_IF_SLAVE or FT_ROBO_IF_COM. * @param dwZyklus Cycle to retrieve analog values (only II). Try 10. * @return The ft device or NULL if error. */ FT_HANDLE OpenFtCommDevice(char *sDevice, long int dwTyp, long int dwZyklus) {//makes a (blocking) comm request to the interface FT_HANDLE ret; unsigned char in[5]; unsigned char on[] = " ft-Robo-ON-V1"; on[0] = 0xA1; #ifdef MBED Serial *dev; switch (sDevice[3]) { case '1': dev = new Serial(p9, p10); break; case '2': dev = new Serial(p13, p14); break; case '3': dev = new Serial(p28, p27); break; // default: dev = new Serial(p9, p10); break; default: dev = &viaUsb; break; } ret = new ft_handle_devices; #else long int dev; if ((dev = open(sDevice, O_RDWR | O_NOCTTY)) < 0) { perror("OpenFtCommDevice open"); return NULL; } if ((ret = (FT_HANDLE) malloc (sizeof(struct ft_handle_devices))) == NULL) { perror("GetFtUsbDeviceHandle malloc"); return NULL; } ret->device = NULL; ret->dev = NULL; #endif ret->type = dwTyp; memset(&ret->transfer_area, 0, sizeof(struct _FT_TRANSFER_AREA)); ret->transfer_area.TransferAktiv = 0; ret->analogcycle = dwZyklus/2.0+0.5; ret->query_time = INTERFACE_QUERY_TIME_SERIAL; ret->transfer_area.RfModulNr = -1; ret->interface_connected = 0; #ifdef MBED ret->lock = 1; //init the semaphore if (dev != &viaUsb) { if (dwTyp == FT_INTELLIGENT_IF || dwTyp == FT_INTELLIGENT_IF_SLAVE || dwTyp == FT_ROBO_IF_IIM) dev->baud(BAUDRATE_II); else // dwTyp == FT_ROBO_IF_COM dev->baud(BAUDRATE_RI); } ret->sdev = dev; if (dwTyp == FT_INTELLIGENT_IF) ret->transfer_area.BusModules = 1; else if (dwTyp == FT_INTELLIGENT_IF_SLAVE) ret->transfer_area.BusModules = 2; printf("about to send '%s'\n", on); if (dwTyp == FT_ROBO_IF_COM) { int sent = write(dev, on, strlen((const char*)on), 100/*ms*/); // int sent = dev->printf("%s", on); printf("sent %d bytes to COM\n", sent); if (sent == strlen((const char*)on)) { if (read(dev, in, 5, 1000/*ms*/) == 5) { // if (dev->scanf("%5c", in) == 1) { does not work, could have to do with NUL chars or needs a lookahead char printf("%02X: interface version: %d.%d.%d.%d\n", in[0], in[4], in[3], in[2], in[1]); if ((in[0] ^ on[0]) == 0x0FFU) { printf("opening of %s OK\n", sDevice); } else { printf("return code is %02X but should be %02X\n", in[0], ~on[0]&0xFF); delete ret; return NULL; } } else { printf("read did not return 5\n"); delete ret; return NULL; } } else { printf("only %d chars were sent i.o %d\n", sent, strlen((const char*)on)); delete ret; return NULL; } } //printf("OpenFtCommDevice: Error communicating with serial\n"); //delete ret; //return NULL; //} #else sem_init(&ret->lock, 0, 1); tcgetattr(dev, &ret->saveioset); /* save current modem settings */ bzero(&ret->newioset, sizeof(struct termios)); ret->newioset.c_cflag = CS8 | CLOCAL | CREAD; if (dwTyp == FT_INTELLIGENT_IF || dwTyp == FT_INTELLIGENT_IF_SLAVE || dwTyp == FT_ROBO_IF_IIM) ret->newioset.c_cflag |= BAUDRATE_II; else // dwTyp == FT_ROBO_IF_COM ret->newioset.c_cflag |= BAUDRATE_RI; ret->newioset.c_oflag = 0; ret->newioset.c_lflag = 0; ret->newioset.c_cc[VTIME] = 1; ret->newioset.c_cc[VMIN] = 0; tcflush(dev, TCIFLUSH); tcsetattr(dev, TCSANOW, &ret->newioset); ret->sdev = dev; if (dwTyp == FT_INTELLIGENT_IF) ret->transfer_area.BusModules = 1; else if (dwTyp == FT_INTELLIGENT_IF_SLAVE) ret->transfer_area.BusModules = 2; if (dwTyp == FT_ROBO_IF_COM && ((write(dev, &on, 14)) != 14 || (read(dev, &in, 5)) != 5 || in[0] != 0x5E)) { fprintf(stderr, "OpenFtCommDevice: Error communicating with serial\n"); free(ret); return NULL; } #endif return ret; } /** * \brief Returns type of the interface * * This function will return the type of the interface that is behind the handle. * * @param hFt Handle of the device * @return NO_FT_DEVICE, FT_INTELLIGENT_IF, FT_INTELLIGENT_IF_SLAVE, FT_ROBO_IF_COM, FT_ROBO_IF_USB, FT_ROBO_IF_IIM, FT_ROBO_IF_OVER_RF, FT_ROBO_IO_EXTENSION or FT_ROBO_RF_DATA_LINK */ long int GetFtDeviceTyp(FT_HANDLE hFt) { if (hFt == NULL) { fprintf(stderr, "GetFtDeviceTyp: No such device\n"); return NO_FT_DEVICE; } return hFt->type; } /** * \brief Returns a string that identifies the interface with human words * * This function will give you a human readable string like "Robo Interface" you can work with. * * @param hFt Handle of the device * @param dest Buffer we can write the string to * @param len Maximum length of this buffer * @return FTLIB_ERR_SUCCESS or a failure */ long int GetFtDeviceTypeString(FT_HANDLE hFt, char *dest, int len) { // Todo: Maybe let usb query the string from the device? if (hFt == NULL) { fprintf(stderr, "GetFtDeviceTyp: No such device\n"); return NO_FT_DEVICE; } switch (GetFtDeviceTyp(hFt)) { case FT_INTELLIGENT_IF: strncpy(dest, "Intelligent Interface", len); break; case FT_INTELLIGENT_IF_SLAVE: strncpy(dest, "Intelligent Interface with slave", len); break; case FT_ROBO_IF_IIM: strncpy(dest, "Robo Interface II mode", len); break; case FT_ROBO_IF_COM: strncpy(dest, "Robo Interface over serial", len); break; case FT_ROBO_IF_USB: strncpy(dest, "Robo Interface over USB", len); break; case FT_ROBO_IO_EXTENSION: strncpy(dest, "Robo IO Extension", len); break; case FT_ROBO_RF_DATA_LINK: strncpy(dest, "Robo RF Datalink", len); break; case FT_ROBO_IF_OVER_RF: strncpy(dest, "Robo Interface over RF Datalink", len); break; default: strncpy(dest, "Unknown", len); } return FTLIB_ERR_SUCCESS; } /** * \brief Opens this USB device. * * This function will try to open the ft USB device that belongs to the ft handle hFt. * You can get the ft handle with GetFtUsbDeviceHandle() or GetFtUsbDeviceHandleSerialNr(). * * @see GetFtUsbDeviceHandle() * @see GetFtUsbDeviceHandleSerialNr() * @param hFt ft USB Device to open * @return Number >= 0 on success, < 0 on error */ long int OpenFtUsbDevice(FT_HANDLE hFt) { #ifdef USE_USB long int ret; if (hFt == NULL) { fprintf(stderr, "OpenFtUsbDevice: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } hFt->device = usb_open(hFt->dev); ret = usb_claim_interface(hFt->device, 0); if (ret < 0) perror("usb_claim_interface"); return ret; #else return FTLIB_ERR_NOT_SUPPORTED; #endif } /** * \brief Close the ft Device * * This function will close the ft Device and free its memory. * * @param hFt Handle of the Device to close. * @return A number < 0 on error. */ long int CloseFtDevice(FT_HANDLE hFt) {//sends a comm request int ret = 0; unsigned char off = 0xA2; unsigned char in[1]; unsigned char buf[1]; if (hFt == NULL) { fprintf(stderr, "CloseFtDevice: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } while (hFt->transfer_area.TransferAktiv != 0) { fprintf(stderr, "Transfer area still active\n"); sleep(1); } switch (hFt->type) { // usb #ifdef USE_USB case FT_ROBO_RF_DATA_LINK: case FT_ROBO_IF_OVER_RF: case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: ret = usb_release_interface(hFt->device, 0); if (ret < 0) { fprintf(stderr, "CloseFtDevice(): Error in usb_release_interface()\n"); break; } ret = usb_close(hFt->device); break; #endif // serial #ifdef MBED case FT_ROBO_IF_COM: if (write(hFt->sdev, &off, 1) != 1 || read(hFt->sdev, in, 1) != 1 || (in[0]^off != 0xFF)) { fprintf(stderr, "CloseFtDevice: Error communicating with serial\n"); } case FT_ROBO_IF_IIM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: delete hFt->sdev; ret = 0; break; #else case FT_ROBO_IF_COM: if ((write(hFt->sdev, &off, 1)) != 1 || (read(hFt->sdev, &in, 1)) != 1 || in[0] != 0x5D) { fprintf(stderr, "CloseFtDevice: Error communicating with serial\n"); } case FT_ROBO_IF_IIM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: tcsetattr(hFt->sdev, TCSANOW, &hFt->saveioset); ret = close(hFt->sdev); break; #endif } #ifdef MBED delete hFt; #else free(hFt); #endif hFt = NULL; return ret; } /** * \brief Library deinitialization (dummy) * * Dummy for compatibility. Only used in original library. * @return Always FTLIB_ERR_SUCCESS */ long int CloseFtLib() { return FTLIB_ERR_SUCCESS; } /** * \brief Check for Library initialization (dummy) * * Dummy for compatibility. Only used in original library. * @return Always FTLIB_ERR_LIB_IS_INITIALIZED since initialization is ignored in this version */ long int IsFtLibInit() { return FTLIB_ERR_LIB_IS_INITIALIZED; } bool test_and_set(int& s) { bool tmp; __disable_irq(); if (tmp = s>0) s--; __enable_irq(); return tmp; } void increment(int& s) { __disable_irq(); s++; __enable_irq(); } #ifdef SPLITTRANSFER //version for mbed with split functionality void ft_handle_devices::FtThreadInit() {//setup buffers for this type of interface FT_TRANSFER_AREA *area = &transfer_area; num_write = ABF_IF_COMPLETE_NUM_WRITE; num_read = ABF_IF_COMPLETE_NUM_READ; usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT; usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN; cycle=0; out[0] = ABF_IF_COMPLETE; area->TransferAktiv = 1; sdev->attach(this, &ft_handle_devices::writeByte, Serial::TxIrq); sdev->attach(this, &ft_handle_devices::readByte, Serial::RxIrq); busy = false; switch (type) { case FT_ROBO_IF_COM: out[0] = 0xf2; num_write = 17; num_read = 21; break; case FT_INTELLIGENT_IF: num_write = 2; break; case FT_INTELLIGENT_IF_SLAVE: num_write = 3; break; #ifdef USE_USB case FT_ROBO_IO_EXTENSION: out[0] = 0xf2; num_write = 6; num_read = 6; break; 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; // init RF // 0x102 == first RF // 0x202 == 2nd RF // ... //ret = usb_control_msg(hFt->device, 0xc0, 0xfb, 0x102, 0x1, in, 2, FT_USB_TIMEOUT); ret = usb_control_msg(hFt->device, 0xc0, 0xfb, hFt->transfer_area.RfModulNr << 8 | 0x02, 0x1, in, 2, FT_USB_TIMEOUT); if (ret != 2) { fprintf(stderr, "%d FtThread: Error initiating RF Module!\n"); area->TransferAktiv = 0; } break; #endif } } extern int trigger_interface; bool ft_handle_devices::guardedFtThreadBegin() {//called every 10ms by the main loop to issue a request, should be non-blocking, guarded by busy flag to avoid multiple pending requests //viaUsb.putc('.'); __disable_irq(); if (busy) { if (trigger_interface > 10) { //interface has not responded within 10 slots or response was missed putc('?',stderr); busy = false; //release the busy flag to reenable the request-reply process } __enable_irq(); return false; //skip the timeslot when previous was not yet handled } busy = true; __enable_irq(); FtThreadBegin();//here the request is sent to the interface return true; } void ft_handle_devices::FtThreadTrigger() { trigger_interface++;//this is polled by the main loop //printf("%d ", trigger_interface); } //here the real data exchange starts void ft_handle_devices::FtThreadBegin() {//called every 10ms to issue a request, should be non-blocking int ii_speed = 0; FT_TRANSFER_AREA *area = &transfer_area; if (!test_and_set(lock)) {//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 } out[1] = area->M_Main; out[2] = (area->MPWM_Main[0] & 0x7) | (area->MPWM_Main[1]<<3 & 0x38) | (area->MPWM_Main[2]<<6 & 0xC0); out[3] = (area->MPWM_Main[2] & 0x1) | (area->MPWM_Main[3]<<1 & 0xE) | (area->MPWM_Main[4]<<4 & 0x70) | (area->MPWM_Main[5]<<7 & 0x80); out[4] = (area->MPWM_Main[5] & 0x3) | (area->MPWM_Main[6]<<2 & 0x1C) | (area->MPWM_Main[7]<<5 & 0xE0); out[5] = area->M_Sub1; out[6] = (area->MPWM_Sub1[0] & 0x7) | (area->MPWM_Sub1[1]<<3 & 0x38) | (area->MPWM_Sub1[2]<<6 & 0xC0); out[7] = (area->MPWM_Sub1[2] & 0x1) | (area->MPWM_Sub1[3]<<1 & 0xE) | (area->MPWM_Sub1[4]<<4 & 0x70) | (area->MPWM_Sub1[5]<<7 & 0x80); out[8] = (area->MPWM_Sub1[5] & 0x3) | (area->MPWM_Sub1[6]<<2 & 0x1C) | (area->MPWM_Sub1[7]<<5 & 0xE0); out[9] = area->M_Sub2; out[10] = (area->MPWM_Sub2[0] & 0x7) | (area->MPWM_Sub2[1]<<3 & 0x38) | (area->MPWM_Sub2[2]<<6 & 0xC0); out[11] = (area->MPWM_Sub2[2] & 0x1) | (area->MPWM_Sub2[3]<<1 & 0xE) | (area->MPWM_Sub2[4]<<4 & 0x70) | (area->MPWM_Sub2[5]<<7 & 0x80); out[12] = (area->MPWM_Sub2[5] & 0x3) | (area->MPWM_Sub2[6]<<2 & 0x1C) | (area->MPWM_Sub2[7]<<5 & 0xE0); out[13] = area->M_Sub3; out[14] = (area->MPWM_Sub3[0] & 0x7) | (area->MPWM_Sub3[1]<<3 & 0x38) | (area->MPWM_Sub3[2]<<6 & 0xC0); out[15] = (area->MPWM_Sub3[2] & 0x1) | (area->MPWM_Sub3[3]<<1 & 0xE) | (area->MPWM_Sub3[4]<<4 & 0x70) | (area->MPWM_Sub3[5]<<7 & 0x80); out[16] = (area->MPWM_Sub3[5] & 0x3) | (area->MPWM_Sub3[6]<<2 & 0x1C) | (area->MPWM_Sub3[7]<<5 & 0xE0); out[17] = 0; out[18] = 0; out[19] = 0; out[20] = 0; out[21] = 0; out[22] = 0; out[23] = 0; out[24] = 0; out[25] = 0; out[26] = 0; out[27] = 0; out[28] = 0; out[29] = 0; out[30] = 0; out[31] = 0; // For the II we need to simulate different speeds here if (type == FT_INTELLIGENT_IF || type == FT_INTELLIGENT_IF_SLAVE) { int iCurMotor; for (iCurMotor = 0; iCurMotor < 7; iCurMotor++) { if (area->MPWM_Main[iCurMotor] < ii_speed) out[1] &= ~(1 << iCurMotor); if (area->MPWM_Sub1[iCurMotor] < ii_speed) out[5] &= ~(1 << iCurMotor); } ii_speed++; if (ii_speed > 7) ii_speed = 0; } if (type == FT_INTELLIGENT_IF) { cycle++; num_read = 1; out[0] = 0xC1; if (cycle % 20) { // EX out[0] = 0xC5; num_read = 3; } else if (cycle % 10) { // EY out[0] = 0xC9; num_read = 3; } } else if (type == FT_INTELLIGENT_IF_SLAVE) { cycle++; num_read = 2; out[0] = 0xC2; out[2] = out[5]; if (cycle % 20) { // EX out[0] = 0xC6; num_read = 4; } else if (cycle % 10) { // EY out[0] = 0xCA; num_read = 4; } } //viaUsb.putc('-'); increment(lock);//release the lock on shared memeory int ret = 0; switch (type) {//send the request #ifdef USE_USB case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: case FT_ROBO_IF_OVER_RF: case FT_ROBO_RF_DATA_LINK: ret = usb_interrupt_write(hFt->device, usb_endpoint_write, out, num_write, FT_USB_TIMEOUT); break; #endif case FT_ROBO_IF_COM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: // ret = write(sdev, out, num_write); //sdev->dmaSend(out, num_write); ret = write();//start the transfer of the 'out' buffer, when complete the read_callback will receive the reply and when the reply is complete FtThreadEnd will be called // viaUsb.putc(';'); break; } if (ret != num_write) { interface_connected = 0; fprintf(stderr, "FtThread: Error writing to the Interface...exiting!\n"); } } void ft_handle_devices::FtThreadEnd() {//called by the receiver/dma callback when the reply is complete int ret = 0; FT_TRANSFER_AREA *area = &transfer_area; switch (type) { //receive the reply #ifdef USE_USB case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: case FT_ROBO_IF_OVER_RF: case FT_ROBO_RF_DATA_LINK: ret = usb_interrupt_read(hFt->device, usb_endpoint_read, in, num_read, FT_USB_TIMEOUT); break; #endif case FT_ROBO_IF_COM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: // ret = read(sdev, in, num_read); ret = num_read; // viaUsb.putc('/'); break; } if (ret != num_read) { interface_connected = 0; fprintf(stderr, "FtThread: Error reading from the Interface\n"); return; } if (!test_and_set(lock)) {//skip when busy busy = false; return; } area->ChangeEg = area->E_Main != in[0] || area->E_Sub1 != in[1] || area->E_Sub2 != in[2] || area->E_Sub3 != in[3]; area->E_Main = in[0]; area->E_Sub1 = in[1]; area->E_Sub2 = in[2]; area->E_Sub3 = in[3]; area->ChangeAn = 1; //assume that analog always changes (noise) area->AX = in[4]; area->AY = in[5]; area->A1 = in[6]; area->A2 = in[7]; area->AX |= (in[8] & 0x3) << 8; area->AY |= (in[8] & 0xC) << 6; area->A1 |= (in[8] & 0x30) << 4; area->A2 |= (in[8] & 0xC0) << 2; area->AZ = in[9]; area->D1 = in[10]; area->D2 = in[11]; area->AV = in[12]; area->AZ |= (in[13] & 0x3) << 8; area->D1 |= (in[13] & 0xC) << 6; area->D2 |= (in[13] & 0x30) << 4; area->AV |= (in[13] & 0xC0) << 2; if (area->IRKeys != in[14]) area->ChangeIr = 1; area->IRKeys = in[14]; area->BusModules = in[15]; // 16 area->AXS1 = in[17]; area->AXS2 = in[18]; area->AXS3 = in[19]; area->AXS1 |= (in[20] & 0x3) << 8; area->AXS2 |= (in[20] & 0xC) << 6; area->AXS3 |= (in[20] & 0x30) << 4; // 21 area->AVS1 = in[22]; area->AVS2 = in[23]; area->AVS3 = in[24]; area->AVS1 |= (in[25] & 0x3) << 8; area->AVS2 |= (in[25] & 0xC) << 6; area->AVS3 |= (in[25] & 0x30) << 4; // 26...42 if (type == FT_INTELLIGENT_IF) { if (cycle % analogcycle) { // EX area->AX = in[1] & (8<<in[2]); } else if (cycle % (2*analogcycle)) { // EY area->AY = in[1] & (8<<in[2]); } } else if (type == FT_INTELLIGENT_IF_SLAVE) { if (cycle % analogcycle) { // EX area->AX = in[1] & (8<<in[2]); } else if (cycle % (2*analogcycle)) { // EY area->AY = in[1] & (8<<in[2]); } } increment(lock); interface_connected = 1; if (ne.NotificationCallback) { // printf("%02X\r", transfer_area.E_Main); (*ne.NotificationCallback)(ne.Context); } busy = false; } void ft_handle_devices::FtThreadFinish() {//called by StopFtTransferArea #ifdef USE_USB if (hFt->type == FT_ROBO_IF_OVER_RF || hFt->type == FT_ROBO_RF_DATA_LINK) { ret = usb_control_msg(hFt->device, 0xc0, 0x21, hFt->transfer_area.RfModulNr << 8, 0, in, 1, FT_USB_TIMEOUT); if (ret != 1 || in[0] != 0xd7) { fprintf(stderr, "Error uninitiating RF Module!\n"); } } #endif #ifdef MBED sdev->attach(0,Serial::RxIrq); sdev->attach(0,Serial::TxIrq); #endif transfer_area.TransferAktiv = 0; } void ft_handle_devices::FtThread() { // ::FtThread(this); // printf("%02X\r", transfer_area.E_Main); // viaUsb.putc('.'); } #endif /** * \brief reset outputs * * Will clear all outputs. * * @return Always FTLIB_ERR_SUCCESS */ long int ResetFtTransfer(FT_HANDLE hFt) { FT_TRANSFER_AREA *area = &hFt->transfer_area; area->M_Main = 0; area->M_Sub1 = 0; area->M_Sub2 = 0; area->M_Sub3 = 0; return FTLIB_ERR_SUCCESS; } /** * \brief Starts the communication thread. * * This function is needed to start the communication with the interface in passive mode. * Get the handle with GetFtUsbDeviceHandle(), GetFtUsbDeviceHandleSerialNr() or OpenFtCommDevice(). * * @see GetFtUsbDeviceHandle() * @see GetFtUsbDeviceHandleSerialNr() * @see OpenFtCommDevice() * @param hFt Handle of the interface. * @param ignored The second argument is ignored in this version. * @return Everything except FTLIB_ERR_SUCCESS indicates an error. */ long int StartFtTransferArea(FT_HANDLE hFt, NOTIFICATION_EVENTS* ev) { int ret; if (hFt == NULL) { fprintf(stderr, "StartFtTransferArea: No such device\n"); return NO_FT_DEVICE; } if (ev) hFt->ne = *ev; //copy the entire struct else memset(&hFt->ne, 0, sizeof(NOTIFICATION_EVENTS)); #ifdef MBED //at least for serial devices another solution must be found. A normal request/reply uses the entire 10 ms, this is OK but the CPU should not wait for it //either a buffer or a DMA scheme must be used to free CPU time, this means that at the beginning of the time slot the req. buffer is prepared and //handed over to IRQ/USB, the reply is gathered in a buffer and when complete the transfer area is updated. hFt->t = new Ticker; //printf("ticker created\n"); hFt->FtThreadInit();//setup buffers and serial handlers //hFt->t->attach_us(hFt, &ft_handle_devices::FtThreadBegin, INTERFACE_QUERY_TIME); hFt->t->attach_us(hFt, &ft_handle_devices::FtThreadTrigger, INTERFACE_QUERY_TIME);//FtThreadTrigger just sets a global variable that is polled by the main loop, which subsequently calls guardedFtThreadBegin printf("thread attached\n"); ret = 0; #else ret = pthread_create(&hFt->t, NULL, (void *)FtThread, hFt); #endif usleep(INTERFACE_QUERY_TIME*10); if (ret != 0) { perror("StartFtTransferArea pthread_create"); return ret; } return FTLIB_ERR_SUCCESS; } /** * \brief Starts the communication thread. * * Since notification are ignored in this version, will just call StartFtTransferArea(). * * @see StartFtTransferArea() */ long int StartFtTransferAreaWithCommunication(FT_HANDLE hFt, NOTIFICATION_EVENTS* ignored) { return StartFtTransferArea(hFt, ignored); } /** * \brief Get the transfer area * * This function will return a pointer to the transfer area of the given handle. * * @param hFt Handle of the device. * @return transfer area or NULL on error. */ FT_TRANSFER_AREA* GetFtTransferAreaAddress(FT_HANDLE hFt) { if (hFt == NULL) { fprintf(stderr, "GetFtTransferAreaAddress: No such device\n"); return NULL; } return &hFt->transfer_area; } /** * \brief Stops the communication thread. * \warning Will block a few microseconds until thread stopped. * * This function will stop the communication thread. * * @see StartFtTransferArea() * @param hFt Handle of the Interface. * @return Everything except FTLIB_ERR_SUCCESS indicates an error. */ long int StopFtTransferArea(FT_HANDLE hFt) { int ret; if (hFt == NULL) { fprintf(stderr, "StopFtTransferArea: No such device\n"); return NO_FT_DEVICE; } #ifdef MBED hFt->t->detach(); delete hFt->t; hFt->FtThreadFinish(); #else usleep(INTERFACE_QUERY_TIME*10); // wait to make sure the last command is send to the interface if (hFt->transfer_area.TransferAktiv == 1) { hFt->transfer_area.TransferAktiv = 2; // cleaner then pthread_cancel() } if ((ret = pthread_join(hFt->t, NULL)) != 0) return ret; #endif return FTLIB_ERR_SUCCESS; } /** * \brief check if transfer is active. * * Check if we are currently communicating with the device. * * @param hFt Handle of the Interface. * @return FTLIB_ERR_THREAD_IS_RUNNING or FTLIB_ERR_THREAD_NOT_RUNNING */ long int IsFtTransferActiv(FT_HANDLE hFt) { if (hFt == NULL) { fprintf(stderr, "StopFtTransferArea: No such device\n"); return NO_FT_DEVICE; } if (hFt->transfer_area.TransferAktiv) return FTLIB_ERR_THREAD_IS_RUNNING; return FTLIB_ERR_THREAD_NOT_RUNNING; } #ifdef USE_DOWNLOAD /** * \brief Upload a program to the interface * * Upload (download from the perspective of the interface) a program to the interface. * * @param hFt Handle of the Interface * @param dwMemBlock Destination 0 (Flash 1), 1 (Flash 2) or 2 (Ram) * @param pbArray Pointer to the program to upload * @param dwSize Size of the program to upload * @param dwParameter 1 to Autostart this program, else 0. * @param pbName Name of the program to upload * @param dwNameLen Length of the name * @return FTLIB_ERR_SUCCESS if you got lucky */ long int DownloadFtProgram(FT_HANDLE hFt, long int dwMemBlock, unsigned char *pbArray, long int dwSize, long int dwParameter, unsigned char *pbName, long int dwNameLen) { int ret; unsigned char buffer[128]; long int i; crc_t crc; int memblockarg; if (hFt == NULL) { fprintf(stderr, "DownloadFtProgram: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } else if (hFt->type != FT_ROBO_IF_USB) { fprintf(stderr, "DownloadFtProgram: Sorry, I can only handle the Robo Interface over USB at this time.\n"); return FTLIB_ERR_NOT_SUPPORTED; } switch (dwMemBlock) { case 0x0: // flash 1 memblockarg = 0x100; if (dwParameter == 1) memblockarg += 0x100; break; case 0x1: // flash 2 memblockarg = 0x101; if (dwParameter == 1) fprintf(stderr, "Warning: Autostart for flash 2 not supported\n"); break; case 0x2: // ram memblockarg = 0x102; if (dwParameter == 1) fprintf(stderr, "Warning: Autostart for RAM not supported\n"); break; case 0xf0: // firmware A memblockarg = 0xf200; break; case 0xf1: // firmware B memblockarg = 0xf201; break; default: fprintf(stderr, "Unknown Memblock Target\n"); return FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK; } // init upload ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x20, 0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); return ret; } if (buffer[0] != 1) { fprintf(stderr, "Error uploading Program: Return value for 0xC0 0xF0 is 0x%x\n", buffer[0]); return FTLIB_ERR_DOWNLOAD; } // write name memset(buffer, 0, 128); // clean buffer if (pbName != NULL) strncpy(buffer, pbName, MIN(dwNameLen, 80)); // copy to buffer, so we not change the original content ret = usb_control_msg(hFt->device, 0x40, 0x10, memblockarg, dwSize/PROGRAM_UPLOAD_PACKET_SIZE, buffer, 80, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0x40 0x10\n"); return ret; } // check ret = usb_control_msg(hFt->device, 0xC0, 0x20, 0x0, 0x0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control ms 0xC0 0x20g\n"); return ret; } if (buffer[0] != dwMemBlock || (buffer[0] == 0 && memblockarg == 0xf200) || (buffer[0] == 1 && memblockarg == 0xf201)) { fprintf(stderr, "Upload Error: Target mismatch\n"); } // write the data for (i=0; dwSize >= PROGRAM_UPLOAD_PACKET_SIZE; i++, dwSize -= PROGRAM_UPLOAD_PACKET_SIZE) { memset(buffer, 0, 128); // clean buffer memcpy(buffer, pbArray + (i*PROGRAM_UPLOAD_PACKET_SIZE), MIN(dwSize, PROGRAM_UPLOAD_PACKET_SIZE)); // make sure we not change the original content crc = crc_init(); crc = crc_update(crc, buffer, PROGRAM_UPLOAD_PACKET_SIZE); crc = crc_finalize(crc); // write 128 byte /*printf("CRC: 0x%x\n", crc); printf("Paket: 0x%x\n", i+1); for(k=0; k<128; k++) { printf("0x%x ", buffer[k]); if ((k+1) % 16 == 0 && k != 0) printf("\n"); } printf("\n");*/ ret = usb_control_msg(hFt->device, 0x40, 0x11, i+1, crc, buffer, PROGRAM_UPLOAD_PACKET_SIZE, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0x40 0x11 0x%x\n", i+1); return ret; } // check ret = usb_control_msg(hFt->device, 0xC0, 0x20, 0x0, 0x0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0x20\n"); return ret; } if (buffer[0] != 1) { fprintf(stderr, "Error uploading Program: Return value for 0xC0, 0x20 is 0x%x\n", buffer[0]); return FTLIB_ERR_DOWNLOAD; } } return FTLIB_ERR_SUCCESS; } /** * \brief Start a program * * Will start a program that has been Successfully uploaded to the interface. * * @param hFt Handle of the Interface * @param dwMemBlock Destination 0 (Flash 1), 1 (Flash 2) or 2 (Ram) * @return FTLIB_ERR_SUCCESS or FTLIB_ERR_IF_NO_PROGRAM */ long int StartFtProgram(FT_HANDLE hFt, long int dwMemBlock) { int ret; unsigned char buffer[2]; if (hFt == NULL) { fprintf(stderr, "StartFtProgram: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: // note: serial documentation says 0xf4 here, sniffer says 0x12 ret = usb_control_msg(hFt->device, 0xc0, 0x12, dwMemBlock, 0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF4\n"); return ret; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; case FT_ROBO_IF_COM: buffer[0] = 0xf4; buffer[1] = dwMemBlock; if ((write(hFt->sdev, &buffer, 2)) != 2 || (read(hFt->sdev, &buffer, 1)) != 1) { return FTLIB_ERR_IF_NO_PROGRAM; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; } return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Stop a program * * Will stop the current running program that has been uploaded to the interface. * * @param hFt Handle of the Interface * @return FTLIB_ERR_SUCCESS or FTLIB_ERR_IF_NO_PROGRAM */ long int StopFtProgram(FT_HANDLE hFt) { int ret; unsigned char buffer[1]; if (hFt == NULL) { fprintf(stderr, "StopFtProgram: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: // note: serial documentation says 0xf8 here, sniffer says 0x13 ret = usb_control_msg(hFt->device, 0xc0, 0x13, 0, 0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0x13\n"); return ret; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; case FT_ROBO_IF_COM: buffer[0] = 0xf8; if ((write(hFt->sdev, &buffer, 1)) != 1 || (read(hFt->sdev, &buffer, 1)) != 1) { return FTLIB_ERR_IF_NO_PROGRAM; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; } return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Delete a program * * Will delete a program that has been uploaded to the interface. * * @param hFt Handle of the Interface * @param dwMemBlock Destination 0 (Flash 1), 1 (Flash 2) or 2 (Ram) * @return FTLIB_ERR_SUCCESS or FTLIB_ERR_IF_NO_PROGRAM */ long int DeleteFtProgram(FT_HANDLE hFt, long int dwMemBlock) { int ret; unsigned char buffer[2]; if (hFt == NULL) { fprintf(stderr, "DeleteFtProgram: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: ret = usb_control_msg(hFt->device, 0xc0, 0xf5, dwMemBlock, 0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF5\n"); return ret; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; case FT_ROBO_IF_COM: buffer[0] = 0xf5; buffer[1] = dwMemBlock; if ((write(hFt->sdev, &buffer, 2)) != 2 || (read(hFt->sdev, &buffer, 1)) != 1) { return FTLIB_ERR_IF_NO_PROGRAM; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; } return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Activate a program * * Will activate a program that has been uploaded to the interface. * * @param hFt Handle of the Interface * @param dwMemBlock Destination 0 (Flash 1) or 1 (Flash 2) * @return FTLIB_ERR_SUCCESS or FTLIB_ERR_IF_NO_PROGRAM */ long int SetFtProgramActiv(FT_HANDLE hFt, long int dwMemBlock) { int ret; unsigned char buffer[1]; if (hFt == NULL) { fprintf(stderr, "SetFtProgramActiv: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: ret = usb_control_msg(hFt->device, 0xc0, 0xf9, dwMemBlock, 0, buffer, 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xf9\n"); return ret; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; case FT_ROBO_IF_COM: buffer[0] = 0xf9; buffer[1] = dwMemBlock; if ((write(hFt->sdev, &buffer, 2)) != 2 || (read(hFt->sdev, &buffer, 1)) != 1) { return FTLIB_ERR_IF_NO_PROGRAM; } if ((buffer[0]) == 0x1) return FTLIB_ERR_SUCCESS; else return FTLIB_ERR_IF_NO_PROGRAM; break; } return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Get the name of a program * * Will write the name of a program that has been uploaded to the interface to a given area. * * @param hFt Handle of the Interface * @param dwMemBlock Destination 0 (Flash 1), 1 (Flash 2) or 2 (Ram) * @param pName Pointer to the area where we can store the name * @param dwSize Size of the area to store the name to * @return FTLIB_ERR_SUCCESS or FTLIB_ERR_IF_NO_PROGRAM */ long int GetFtProgramName(FT_HANDLE hFt, long int dwMemBlock, long int dwSize, void *pName) { int ret; unsigned char buffer[dwSize+1]; if (hFt == NULL) { fprintf(stderr, "GetFtProgramName: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: ret = usb_control_msg(hFt->device, 0xc0, 0xfa, dwMemBlock, 0, buffer, dwSize + 1, FT_USB_TIMEOUT_LONG); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xFA\n"); return ret; } memcpy(pName, buffer+1, ret-1); if (buffer[0] == 0x1) return FTLIB_ERR_SUCCESS; if (buffer[0] == 0xf3) return FTLIB_ERR_IF_NO_PROGRAM; return buffer[1]; break; case FT_ROBO_IF_COM: buffer[0] = 0xfa; buffer[1] = dwMemBlock; if ((write(hFt->sdev, &buffer, 2)) != 2 || (ret = read(hFt->sdev, &buffer, dwSize+1)) < 0 || buffer[0] != 0x01) { return FTLIB_ERR_IF_NO_PROGRAM; } memcpy(pName, buffer+1, ret-1); if (buffer[0] == 0x1) return FTLIB_ERR_SUCCESS; break; } return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Checks if a program is running * * Checks if a program is currently running. * * @param hFt Handle of the Interface * @param num Area where we can store the number of the running program. * @return 1 if a program is running, else 0 */ int GetFtStatus(FT_HANDLE hFt, int *num) { int ret; unsigned char buffer[3]; if (hFt == NULL) { fprintf(stderr, "GetFtStatus: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: // test replace 0xf0 with 0x50 ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x3, 0, buffer, 3, FT_USB_TIMEOUT); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); return ret; } ret = buffer[1]; *num = buffer[2]; break; case FT_ROBO_IF_COM: buffer[0] = 0xf0; buffer[1] = 0x3; if ((write(hFt->sdev, &buffer, 2)) != 2 || (ret = read(hFt->sdev, &buffer, 3)) < 0 || buffer[0] != 0xfc) { return ret; } ret = buffer[1]; *num = buffer[2]; break; default: return FTLIB_ERR_NOT_SUPPORTED; } return ret; } #endif //USE_DOWNLOAD /** * \brief Get the firmware number of this interface. * * Returns the firmware number of the interface squashed into a single int. * * @param hFt Handle of the Interface * @return Firmware number as int byte4 | byte3 | byte2 | byte1, 0 on error. */ long int GetFtFirmware(FT_HANDLE hFt) {//makes a blocking comm request int ret; unsigned char buffer[35] = { 0 }; long int firmware = 0; if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: return 0; #ifdef USE_USB case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: case FT_ROBO_RF_DATA_LINK: ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x1, 0, buffer, 5, FT_USB_TIMEOUT); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); return 0; } firmware = buffer[1] | buffer[2]<<8 | buffer[3]<<16 | buffer[4]<<24; break; case FT_ROBO_IF_OVER_RF: ret = usb_control_msg(hFt->device, 0xc0, 0x52, hFt->transfer_area.RfModulNr<<8 | 0x05, 0, buffer, 35, FT_USB_TIMEOUT); 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 firmware = buffer[23]<<24 | buffer[22]<<16 | buffer[21]<<8 | buffer[20]; } break; #endif case FT_ROBO_IF_COM: buffer[0] = 0xf0; buffer[1] = 0x01; #ifdef MBED //printf("requesting FW\n"); //ret = hFt->sdev->printf("%2c", buffer); ret = write(hFt->sdev, buffer, 2); // printf("request was sent %d\n", ret); #else ret = write(hFt->sdev, &buffer, 2); #endif if (ret != 2) { fprintf(stderr, "Error writing msg 0xF0 0x01\n"); return 0; } #ifdef MBED //ret = hFt->sdev->scanf("%5c", buffer)==1 ? 5 : 0 ; ret = read(hFt->sdev, buffer, 5); #else ret = read(hFt->sdev, &buffer, 5); #endif if (ret != 5) { fprintf(stderr, "Error reading msg 0xF0 0x01\n"); return 0; } firmware = buffer[1] | buffer[2]<<8 | buffer[3]<<16 | buffer[4]<<24; // printf("fw: %ld\n", firmware); break; default: return FTLIB_ERR_NOT_SUPPORTED; } return firmware; } /** * \brief Get the firmware number of this interface. * * Returns the firmware number of the interface with this handle. * The allocated space should be freed with free() later. * * @param hFt Handle of the Interface * @return Pointer to a string with the firmware */ char *GetFtFirmwareStrg(FT_HANDLE hFt) { long int ifw = GetFtFirmware(hFt); char *s = (char *)malloc(16); int byte1 = ifw & 0xff; int byte2 = (ifw & 0xff00) >> 8; int byte3 = (ifw & 0xff0000) >> 16; int byte4 = (ifw & 0xff000000) >> 24; snprintf(s, 16, "%d.%02d.%02d.%02d", byte4, byte3, byte2, byte1); return s; } #ifndef NOTNOW /** * \brief Get the serial number of this interface. * * Returns the serial number of the interface squashed into a single int. * * @param hFt Handle of the Interface * @return Serial number as int byte4 | byte3 | byte2 | byte1, 0 on error. */ long int GetFtSerialNr(FT_HANDLE hFt) { int ret; unsigned char buffer[35] = { 0 }; long int serial = 0; if (hFt == NULL) { fprintf(stderr, "GetFtSerialNr: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: return 0; break; case FT_ROBO_IF_USB: ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x2, 0, buffer, 5, FT_USB_TIMEOUT); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); return 0; } serial = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000; break; case FT_ROBO_IO_EXTENSION: ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x2, 0, buffer, 14, FT_USB_TIMEOUT); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0xF0\n"); return 0; } serial = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000; break; case FT_ROBO_RF_DATA_LINK: ret = usb_control_msg(hFt->device, 0xc0, 0xf0, 0x2, 0, buffer, 14, FT_USB_TIMEOUT); if (ret < 0) { fprintf(stderr, "Error sending control msg 0xC0 0x52\n"); return 0; } serial = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000; break; case FT_ROBO_IF_OVER_RF: ret = usb_control_msg(hFt->device, 0xc0, 0x52, hFt->transfer_area.RfModulNr<<8 | 0x05, 0, buffer, 35, FT_USB_TIMEOUT); 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 serial = buffer[6]*1000000 + buffer[5]*10000 + buffer[4]*100 + buffer[3]; } break; case FT_ROBO_IF_COM: buffer[0] = 0xf0; buffer[1] = 0x02; ret = write(hFt->sdev, &buffer, 2); if (ret != 2) { fprintf(stderr, "Error writing msg 0xF0 0x02\n"); return 0; } ret = read(hFt->sdev, &buffer, 5); if (ret != 5) { fprintf(stderr, "Error reading msg 0xF0 0x02\n"); return 0; } serial = buffer[1] + buffer[2]*100 + buffer[3]*10000 + buffer[4]*1000000; break; default: return FTLIB_ERR_NOT_SUPPORTED; } return serial; } /** * \brief Get the serial number of this interface. * * Returns the serial number of the interface with this handle. * The allocated space should be freed with free() later. * * @param hFt Handle of the Interface * @return Pointer to a string with the serial */ char *GetFtSerialNrStrg(FT_HANDLE hFt) { long int ifw = GetFtSerialNr(hFt); char *s = (char *)malloc(16); int byte1, byte2, byte3, byte4; byte1 = ifw % 100; ifw /= 100; byte2 = ifw % 100; ifw /= 100; byte3 = ifw % 100; ifw /= 100; byte4 = ifw % 100; ifw /= 100; snprintf(s, 16, "%d.%02d.%02d.%02d", byte4, byte3, byte2, byte1); return s; } /** * \brief Close all ft devices * * Dummy. Can't be supported. Only used in original library. * * @return Always FTLIB_ERR_NOT_SUPPORTED */ long int CloseAllFtDevices() { return FTLIB_ERR_NOT_SUPPORTED; } /** * \brief Set the inputs D1 and D2 to distance oder voltage measuring * * This function allows to enable the inputs D1 and D2 to measure distances. * Must be called before StartFtTransferArea() * * Note by Hardware Vendor: * "Since the operating mode of the D1 / D2 inputs can be set by means of software, we recommend that no * voltage be supplied 'directly' to these connections in order to avoid damage to the interface during software * errors. Since the inputs are highly resistive, a resistance of approximately 200 Ohm - 470 Ohm should be * directly connected to the D1 / D2 socket (series connection). We recommend to connect the voltage range to * be measured 'behind' it." * * @param hFt Handle of the Interface * @param dwMode Set mode to IF_DS_INPUT_VOLTAGE (measure voltage) or IF_DS_INPUT_DISTANCE (measure distance) * @param dwTol1 Range of tolerance for D1. Try IF_DS_INPUT_TOL_STD (20). * @param dwTol2 Range of tolerance for D2. Try IF_DS_INPUT_TOL_STD (20). * @param dwLevel1 Threshold for D1. Try 100. * @param dwLevel2 Threshold for D2. Try 100. * @param dwRepeat1 Repition value for D1. Try IF_DS_INPUT_REP_STD (3). * @param dwRepeat2 Repition value for D2. Try IF_DS_INPUT_REP_STD (3). * @return FTLIB_ERR_SUCCESS on success */ long int SetFtDistanceSensorMode(FT_HANDLE hFt, long int dwMode, long int dwTol1, long int dwTol2, long int dwLevel1, long int dwLevel2, long int dwRepeat1, long int 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 int i; 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; if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: ret = usb_control_msg(hFt->device, 0x40, 0xf1, 0x1, dwMode, buffer+1, 8, FT_USB_TIMEOUT); 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 = usb_control_msg(hFt->device, 0x40, 0x53, hFt->transfer_area.RfModulNr<<8 | 0x01, 0, buffer, 34, FT_USB_TIMEOUT); if (ret != 34) { fprintf(stderr, "Error sending control msg 0x40 0x53\n"); return ret; } break; case FT_ROBO_IF_COM: // move data in array for two bytes for (i=10; i>=3; i--) { buffer[i] = buffer[i-2]; } buffer[0] = 0xf1; buffer[1] = 0x01; buffer[2] = dwMode; if ((write(hFt->sdev, &buffer, 11)) != 11 || (read(hFt->sdev, &buffer, 1)) != 1 || buffer[0] != 0x01) { fprintf(stderr, "SetFtDistanceSensorMode: Error communicating with serial\n"); return buffer[0]; } break; default: return FTLIB_ERR_NOT_SUPPORTED; } usleep(100000); // wait before continue, else it doesn't always work return FTLIB_ERR_SUCCESS; } /** * \brief Sets the frequency and call sign for a Robo Interface or RF Data Link. * * Sets the frequency and call sign which allows to control multiple Interfaces at one RF Data Link. * The value won't be lost on power failure. * * @param hFt Handle of the Interface * @param frequency to use. May be between 2 and 80. * @param callSign call sign for this Interface. May be between 1 and 8. (ignored for the RF Data Link) * @return FTLIB_ERR_SUCCESS on success */ long int SetRFMode(FT_HANDLE hFt, long int frequency, long int callSign) { int ret; unsigned char buffer[5]; if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } else if (frequency < 2 || frequency > 80) { return FTLIB_ERR_INVALID_PARAM; } else if (callSign > 8) { return FTLIB_ERR_INVALID_PARAM; } switch (hFt->type) { case FT_ROBO_RF_DATA_LINK: ret = usb_control_msg(hFt->device, 0xc0, 0xfb, 1, frequency, buffer, 2, FT_USB_TIMEOUT); if (ret != 2 || buffer[0] != 0xfe || buffer[1] != 0) { fprintf(stderr, "Error sending control msg 0xc0 0xfb\n"); return ret; } break; case FT_ROBO_IF_USB: // not or-ing 1 to frequency seems to disable the modul ret = usb_control_msg(hFt->device, 0xc0, 0xfb, (callSign<<8) | 1, (1<<8) | frequency, buffer, 2, FT_USB_TIMEOUT); if (ret != 2 || buffer[0] != 0xfe || buffer[1] != 0) { fprintf(stderr, "Error sending control msg 0xc0 0xfb\n"); return ret; } break; case FT_ROBO_IF_COM: buffer[0] = 0xfb; buffer[1] = 0x1; buffer[2] = 0x7f; buffer[3] = frequency; buffer[4] = callSign; if ((write(hFt->sdev, &buffer, 5)) != 5 || (ret = read(hFt->sdev, &buffer, 2)) != 2 || buffer[0] != 0xfe) { fprintf(stderr, "SetRFMode: Error communicating with serial\n"); return ret; } break; default: return FTLIB_ERR_NOT_SUPPORTED; } return FTLIB_ERR_SUCCESS; } /** * \brief Gets the frequency and call sign of a Robo Interface or RF Data Link. * * Sets the frequency and call sign which allows to control multiple Interfaces at one RF Data Link. * * @param hFt Handle of the Interface * @param frequency Points to a place to store the frequency. * @param callSign Points to a place to store the callSign. (Value will be 0 for the RF Data Link) * @return FTLIB_ERR_SUCCESS on success */ long int GetRFMode(FT_HANDLE hFt, long int *frequency, long int *callSign) { int ret; unsigned char buffer[8]; if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: case FT_ROBO_RF_DATA_LINK: ret = usb_control_msg(hFt->device, 0xc0, 0xfb, 0x81, 0, buffer, 8, FT_USB_TIMEOUT); if (ret != 8) { fprintf(stderr, "Error sending control msg 0xc0 0xfb\n"); return ret; } *frequency = buffer[6]; *callSign = buffer[7]; break; case FT_ROBO_IF_COM: buffer[0] = 0xfb; buffer[1] = 0x81; if ((write(hFt->sdev, &buffer, 2)) != 2 || (ret = read(hFt->sdev, &buffer, 8)) != 8 || buffer[0] != 0x7e) { fprintf(stderr, "GetRFMode: Error communicating with serial\n"); return ret; } *frequency = buffer[6]; *callSign = buffer[7]; break; default: return FTLIB_ERR_NOT_SUPPORTED; } return FTLIB_ERR_SUCCESS; } /** * \brief Switches between the real serial and 0001 of a device. * * Every ft Interface is shipped with 0001 as serial. * Nevertheless each has its own serial which can be activated. * * @param hFt Handle of the Interface * @param bOn 0 to use 0001, else the real serial * @return FTLIB_ERR_SUCCESS on success */ long int SetRealSerial(FT_HANDLE hFt, unsigned char bOn) { int ret; // on: 2 0xd2 0x3a // off: 1 0x81 0x6f // RF: 2 d8 77 vs 1 8b 22 // Whats the number? // SetSerial(hFt, 5386); unsigned char buffer[16] = {0xaf, 0x83, 0x55, 0xa1, 1, 0, 0, 0, 1, 0x81, 0x6f, 0, 0, 0, 0, 0}; if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); return FTLIB_ERR_PORT_NUMBER_IS_NULL; } switch (hFt->type) { case FT_ROBO_IF_USB: if (bOn) { buffer[8] = 2; buffer[9] = 0xd2; buffer[10] = 0x3a; } else { buffer[8] = 1; buffer[9] = 0x81; buffer[10] = 0x6f; } ret = usb_control_msg(hFt->device, 0x40, 0xaf, 0x83, 0, buffer, 16, 200000); if (ret != 16) { fprintf(stderr, "Error sending control msg 0x40 0xaf\n"); return ret; } break; case FT_ROBO_IF_OVER_RF: if (bOn) { buffer[8] = 2; buffer[9] = 0xd8; buffer[10] = 0x77; } else { buffer[8] = 1; buffer[9] = 0x8b; buffer[10] = 0x22; } ret = usb_control_msg(hFt->device, 0x40, 0xaf, 0x83, 0, buffer, 16, 200000); if (ret != 16) { fprintf(stderr, "Error sending control msg 0x40 0xaf\n"); return ret; } break; case FT_ROBO_IO_EXTENSION: if (bOn) { buffer[8] = 2; buffer[9] = 0x5f; buffer[10] = 0x28; } else { buffer[8] = 1; buffer[9] = 0x0c; buffer[10] = 0x7d; } ret = usb_control_msg(hFt->device, 0x40, 0xaf, 0x83, 0, buffer, 16, 200000); if (ret != 16) { fprintf(stderr, "Error sending control msg 0x40 0xaf\n"); return ret; } break; case FT_ROBO_IF_COM: if ((write(hFt->sdev, &buffer, 16)) != 16 || (ret = read(hFt->sdev, &buffer, 2)) != 2 || buffer[0] != 0x7c) { fprintf(stderr, "SetRealSerial: Error communicating with serial\n"); return ret; } break; default: return FTLIB_ERR_NOT_SUPPORTED; } return FTLIB_ERR_SUCCESS; } /** * @brief Gets the Manufacturer of the Interface * * Will return the Manufacturer of a fischertechnik USB device. * The allocated space should be freed with free() later. * * @param hFt Handle of the Interface * @return Pointer to the string with the name */ char *GetFtManufacturerStrg(FT_HANDLE hFt) { char *buffer = (char *)malloc(128); memset(buffer, '\0', 128); if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); } switch (hFt->type) { case FT_ROBO_IF_USB: case FT_ROBO_RF_DATA_LINK: case FT_ROBO_IF_OVER_RF: usb_get_string_simple(hFt->device, 1, buffer, 128); break; } return buffer; } /** * @brief Gets the short name of the Interface * * Will return the short name of a fischertechnik USB device. * The allocated space should be freed with free() later. * * @param hFt Handle of the Interface * @return Pointer to the string with the name */ char *GetFtShortNameStrg(FT_HANDLE hFt) { char *buffer = (char *)malloc(128); memset(buffer, '\0', 128); if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); } switch (hFt->type) { case FT_ROBO_IF_USB: case FT_ROBO_RF_DATA_LINK: case FT_ROBO_IF_OVER_RF: usb_get_string_simple(hFt->device, 5, buffer, 128); break; } return buffer; } /** * @brief Gets the long name of the Interface * * Will return the long name of a fischertechnik USB device. * The allocated space should be freed with free() later. * * @param hFt Handle of the Interface * @return Pointer to the string with the name */ char *GetFtLongNameStrg(FT_HANDLE hFt) { char *buffer = (char *)malloc(128); memset(buffer, '\0', 128); if (hFt == NULL) { fprintf(stderr, "GetFtFirmware: No such device\n"); } switch (hFt->type) { case FT_ROBO_IF_USB: case FT_ROBO_RF_DATA_LINK: case FT_ROBO_IF_OVER_RF: usb_get_string_simple(hFt->device, 2, buffer, 128); break; } return buffer; } #endif //NOTNOW /** * @brief Tells if we successfuly got a connection to the Interface * * @param hFt Handle of the Interface * @return 0 if the Interface is not connected */ char IsFtInterfaceConnected(FT_HANDLE hFt) { return hFt->interface_connected; } /** * @brief Gets the description of an error * * Will return a description of an error. * The allocated space should be freed with free() later. * * The return value is the constant as string if parameter dwTyp is 0, * else a verbose description of the error. * * @param dwErrorCode Error Code * @param dwTyp Type of the return value (see description) * @return Pointer to a string (see description) */ char *GetFtLibErrorString(long int dwErrorCode, long int dwTyp) { char *buffer = (char *)malloc(128); switch (dwErrorCode) { case FTLIB_ERR_IF_NO_PROGRAM: if (dwTyp) strncpy(buffer, "There is no program stored to work with", 128); else strncpy(buffer, "FTLIB_ERR_IF_NO_PROGRAM", 128); break; case FTLIB_ERR_SUCCESS: if (dwTyp) strncpy(buffer, "Everything is fine", 128); else strncpy(buffer, "FTLIB_ERR_SUCCESS", 128); break; case FTLIB_ERR_THREAD_IS_RUNNING: if (dwTyp) strncpy(buffer, "Thread has been started successfully", 128); else strncpy(buffer, "FTLIB_ERR_THREAD_IS_RUNNING", 128); break; case FTLIB_ERR_DOWNLOAD: if (dwTyp) strncpy(buffer, "Failed to upload the program", 128); else strncpy(buffer, "FTLIB_ERR_DOWNLOAD", 128); break; case FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK: if (dwTyp) strncpy(buffer, "Bad target to upload the program to", 128); else strncpy(buffer, "FTLIB_ERR_DOWNLOAD_WRONG_MEM_BLOCK", 128); break; case FTLIB_ERR_INVALID_PARAM: if (dwTyp) strncpy(buffer, "A parameter specified has a wrong value", 128); else strncpy(buffer, "FTLIB_ERR_INVALID_PARAM", 128); break; case FTLIB_ERR_LIB_IS_INITIALIZED: if (dwTyp) strncpy(buffer, "This library has been initialized", 128); else strncpy(buffer, "FTLIB_ERR_LIB_IS_INITIALIZED", 128); break; case FTLIB_ERR_NOT_SUPPORTED: if (dwTyp) strncpy(buffer, "The requested action is not supported", 128); else strncpy(buffer, "FTLIB_ERR_NOT_SUPPORTED", 128); break; case FTLIB_ERR_PORT_NUMBER_IS_NULL: if (dwTyp) strncpy(buffer, "No handle given", 128); else strncpy(buffer, "FTLIB_ERR_PORT_NUMBER_IS_NULL", 128); break; case FTLIB_ERR_THREAD_NOT_RUNNING: if (dwTyp) strncpy(buffer, "Unable to start the thread", 128); else strncpy(buffer, "FTLIB_ERR_THREAD_NOT_RUNNING", 128); break; default: strncpy(buffer, "Unknown", 128); } return buffer; } /** \cond doxygen ignore start */ //! \todo long int SetFtDeviceCommMode(FT_HANDLE hFt, long int dwMode, long int dwParameter, unsigned short *puiValue) { return 0; } //! \todo long int GetFtDeviceSetting(FT_HANDLE hFt, FT_SETTING *pSet) { return 0; } //! \todo long int SetFtDeviceSetting(FT_HANDLE hFt, FT_SETTING *pSet) { return 0; } //! \todo long int SendFtMessage(FT_HANDLE hFt, unsigned char bHwId, unsigned char bSubId, long int dwMessage, long int dwWaitTime, long int dwOption) { return 0; } //! \todo long int ClearFtMessageBuffer(FT_HANDLE hFt) { return 0; } //! \todo long int GetFtMemoryLayout(FT_HANDLE hFt, unsigned char* pbArray, long int dwSize) { return 0; } //! \todo long int GetFtMemoryData(FT_HANDLE hFt, unsigned char * pbArray, long int dwSize, long int dwAddress) { return 0; } //! \todo long int WriteFtMemoryData(FT_HANDLE hFt, long int dwData, long int dwAddress) { return 0; } #ifndef SPLITTRANSFER /** \cond doxygen ignore start */ static void *FtThread(FT_HANDLE hFt) { FT_TRANSFER_AREA *area = &hFt->transfer_area; int ret; unsigned char out[ABF_IF_COMPLETE_NUM_WRITE]; //= {ABF_IF_COMPLETE,1,0x07,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unsigned char in[ABF_IF_COMPLETE_NUM_READ]; int num_write = ABF_IF_COMPLETE_NUM_WRITE; int num_read = ABF_IF_COMPLETE_NUM_READ; int usb_endpoint_write = FT_ENDPOINT_INTERRUPT_OUT; int usb_endpoint_read = FT_ENDPOINT_INTERRUPT_IN; int i=0; int ii_speed = 0; out[0] = ABF_IF_COMPLETE; area->TransferAktiv = 1; switch (hFt->type) { case FT_ROBO_IF_COM: out[0] = 0xf2; num_write = 17; num_read = 21; break; case FT_INTELLIGENT_IF: num_write = 2; break; case FT_INTELLIGENT_IF_SLAVE: num_write = 3; break; #ifdef USE_USB case FT_ROBO_IO_EXTENSION: out[0] = 0xf2; num_write = 6; num_read = 6; break; 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; // init RF // 0x102 == first RF // 0x202 == 2nd RF // ... //ret = usb_control_msg(hFt->device, 0xc0, 0xfb, 0x102, 0x1, in, 2, FT_USB_TIMEOUT); ret = usb_control_msg(hFt->device, 0xc0, 0xfb, hFt->transfer_area.RfModulNr << 8 | 0x02, 0x1, in, 2, FT_USB_TIMEOUT); if (ret != 2) { fprintf(stderr, "%d FtThread: Error initiating RF Module!\n"); area->TransferAktiv = 0; } break; #endif } //here the real data exchange starts #ifdef MBED //viaUsb.putc('.'); /*while (area->TransferAktiv == 1)*/ { //procedure runs only once if (!test_and_set(hFt->lock)) //return when busy return 0;//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 #else while (area->TransferAktiv == 1) {//thread runs continuously sem_wait(&hFt->lock);//wait when busy #endif out[1] = area->M_Main; out[2] = (area->MPWM_Main[0] & 0x7) | (area->MPWM_Main[1]<<3 & 0x38) | (area->MPWM_Main[2]<<6 & 0xC0); out[3] = (area->MPWM_Main[2] & 0x1) | (area->MPWM_Main[3]<<1 & 0xE) | (area->MPWM_Main[4]<<4 & 0x70) | (area->MPWM_Main[5]<<7 & 0x80); out[4] = (area->MPWM_Main[5] & 0x3) | (area->MPWM_Main[6]<<2 & 0x1C) | (area->MPWM_Main[7]<<5 & 0xE0); out[5] = area->M_Sub1; out[6] = (area->MPWM_Sub1[0] & 0x7) | (area->MPWM_Sub1[1]<<3 & 0x38) | (area->MPWM_Sub1[2]<<6 & 0xC0); out[7] = (area->MPWM_Sub1[2] & 0x1) | (area->MPWM_Sub1[3]<<1 & 0xE) | (area->MPWM_Sub1[4]<<4 & 0x70) | (area->MPWM_Sub1[5]<<7 & 0x80); out[8] = (area->MPWM_Sub1[5] & 0x3) | (area->MPWM_Sub1[6]<<2 & 0x1C) | (area->MPWM_Sub1[7]<<5 & 0xE0); out[9] = area->M_Sub2; out[10] = (area->MPWM_Sub2[0] & 0x7) | (area->MPWM_Sub2[1]<<3 & 0x38) | (area->MPWM_Sub2[2]<<6 & 0xC0); out[11] = (area->MPWM_Sub2[2] & 0x1) | (area->MPWM_Sub2[3]<<1 & 0xE) | (area->MPWM_Sub2[4]<<4 & 0x70) | (area->MPWM_Sub2[5]<<7 & 0x80); out[12] = (area->MPWM_Sub2[5] & 0x3) | (area->MPWM_Sub2[6]<<2 & 0x1C) | (area->MPWM_Sub2[7]<<5 & 0xE0); out[13] = area->M_Sub3; out[14] = (area->MPWM_Sub3[0] & 0x7) | (area->MPWM_Sub3[1]<<3 & 0x38) | (area->MPWM_Sub3[2]<<6 & 0xC0); out[15] = (area->MPWM_Sub3[2] & 0x1) | (area->MPWM_Sub3[3]<<1 & 0xE) | (area->MPWM_Sub3[4]<<4 & 0x70) | (area->MPWM_Sub3[5]<<7 & 0x80); out[16] = (area->MPWM_Sub3[5] & 0x3) | (area->MPWM_Sub3[6]<<2 & 0x1C) | (area->MPWM_Sub3[7]<<5 & 0xE0); out[17] = 0; out[18] = 0; out[19] = 0; out[20] = 0; out[21] = 0; out[22] = 0; out[23] = 0; out[24] = 0; out[25] = 0; out[26] = 0; out[27] = 0; out[28] = 0; out[29] = 0; out[30] = 0; out[31] = 0; // For the II we need to simulate different speeds here if (hFt->type == FT_INTELLIGENT_IF || hFt->type == FT_INTELLIGENT_IF_SLAVE) { int iCurMotor; for (iCurMotor = 0; iCurMotor < 7; iCurMotor++) { if (area->MPWM_Main[iCurMotor] < ii_speed) out[1] &= ~(1 << iCurMotor); if (area->MPWM_Sub1[iCurMotor] < ii_speed) out[5] &= ~(1 << iCurMotor); } ii_speed++; if (ii_speed > 7) ii_speed = 0; } if (hFt->type == FT_INTELLIGENT_IF) { i++; num_read = 1; out[0] = 0xC1; if (i % 20) { // EX out[0] = 0xC5; num_read = 3; } else if (i % 10) { // EY out[0] = 0xC9; num_read = 3; } } else if (hFt->type == FT_INTELLIGENT_IF_SLAVE) { i++; num_read = 2; out[0] = 0xC2; out[2] = out[5]; if (i % 20) { // EX out[0] = 0xC6; num_read = 4; } else if (i % 10) { // EY out[0] = 0xCA; num_read = 4; } } #ifdef MBED //viaUsb.putc('-'); increment(hFt->lock);//release the lock on shared memeory #else sem_post(&hFt->lock); #endif ret = 0; switch (hFt->type) {//send the request #ifdef USE_USB case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: case FT_ROBO_IF_OVER_RF: case FT_ROBO_RF_DATA_LINK: ret = usb_interrupt_write(hFt->device, usb_endpoint_write, out, num_write, FT_USB_TIMEOUT); break; #endif case FT_ROBO_IF_COM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: #ifdef MBED //ret = hFt->sdev->printf("%*c", num_write, out); ret = write(hFt->sdev, out, num_write); // viaUsb.putc(';'); #else ret = write(hFt->sdev, &out, num_write); #endif break; } if (ret != num_write) { hFt->interface_connected = 0; fprintf(stderr, "FtThread: Error writing to the Interface...exiting!\n"); #ifdef MBED return 0; #else break; #endif } ret = 0; switch (hFt->type) { //receive the reply #ifdef USE_USB case FT_ROBO_IF_USB: case FT_ROBO_IO_EXTENSION: case FT_ROBO_IF_OVER_RF: case FT_ROBO_RF_DATA_LINK: ret = usb_interrupt_read(hFt->device, usb_endpoint_read, in, num_read, FT_USB_TIMEOUT); break; #endif case FT_ROBO_IF_COM: case FT_INTELLIGENT_IF: case FT_INTELLIGENT_IF_SLAVE: #ifdef MBED //ret = hFt->sdev->scanf("%*c", num_read, in)==1 ? num_read : 0 ; ret = read(hFt->sdev, in, num_read); // viaUsb.putc('/'); #else ret = read(hFt->sdev, &in, num_read); #endif break; } if (ret != num_read) { hFt->interface_connected = 0; fprintf(stderr, "FtThread: Error reading from the Interface\n"); #ifdef MBED return 0; #else usleep(hFt->query_time); continue; #endif } #ifdef MBED if (!test_and_set(hFt->lock))//skip when busy return 0; #else sem_wait(&hFt->lock);//wait when busy #endif area->E_Main = in[0]; area->E_Sub1 = in[1]; area->E_Sub2 = in[2]; area->E_Sub3 = in[3]; area->AX = in[4]; area->AY = in[5]; area->A1 = in[6]; area->A2 = in[7]; area->AX |= (in[8] & 0x3) << 8; area->AY |= (in[8] & 0xC) << 6; area->A1 |= (in[8] & 0x30) << 4; area->A2 |= (in[8] & 0xC0) << 2; area->AZ = in[9]; area->D1 = in[10]; area->D2 = in[11]; area->AV = in[12]; area->AZ |= (in[13] & 0x3) << 8; area->D1 |= (in[13] & 0xC) << 6; area->D2 |= (in[13] & 0x30) << 4; area->AV |= (in[13] & 0xC0) << 2; area->IRKeys = in[14]; area->BusModules = in[15]; // 16 area->AXS1 = in[17]; area->AXS2 = in[18]; area->AXS3 = in[19]; area->AXS1 |= (in[20] & 0x3) << 8; area->AXS2 |= (in[20] & 0xC) << 6; area->AXS3 |= (in[20] & 0x30) << 4; // 21 area->AVS1 = in[22]; area->AVS2 = in[23]; area->AVS3 = in[24]; area->AVS1 |= (in[25] & 0x3) << 8; area->AVS2 |= (in[25] & 0xC) << 6; area->AVS3 |= (in[25] & 0x30) << 4; // 26...42 if (hFt->type == FT_INTELLIGENT_IF) { if (i % hFt->analogcycle) { // EX area->AX = in[1] & (8<<in[2]); } else if (i % (2*hFt->analogcycle)) { // EY area->AY = in[1] & (8<<in[2]); } } else if (hFt->type == FT_INTELLIGENT_IF_SLAVE) { if (i % hFt->analogcycle) { // EX area->AX = in[1] & (8<<in[2]); } else if (i % (2*hFt->analogcycle)) { // EY area->AY = in[1] & (8<<in[2]); } } #ifdef MBED increment(hFt->lock); hFt->interface_connected = 1; #else sem_post(&hFt->lock); hFt->interface_connected = 1; usleep(hFt->query_time); #endif }//end of the while loop (end of task) #ifdef USE_USB if (hFt->type == FT_ROBO_IF_OVER_RF || hFt->type == FT_ROBO_RF_DATA_LINK) { ret = usb_control_msg(hFt->device, 0xc0, 0x21, hFt->transfer_area.RfModulNr << 8, 0, in, 1, FT_USB_TIMEOUT); if (ret != 1 || in[0] != 0xd7) { fprintf(stderr, "Error uninitiating RF Module!\n"); } } #endif #ifdef MBED return 0; #else hFt->transfer_area.TransferAktiv = 0; pthread_exit((void *) 0); #endif } void ft_handle_devices::FtThread() { ::FtThread(this); // printf("%02X\r", transfer_area.E_Main); // viaUsb.putc('.'); } /** \endcond doxygen ignore end */ #endif /** \endcond doxygen ignore end */