Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.
Diff: libft.c
- Revision:
- 0:7f26f0680202
- Child:
- 1:2c9d412ad471
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libft.c Fri Dec 31 14:01:14 2010 +0000 @@ -0,0 +1,2802 @@ +//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 +extern Serial viaUsb; +#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; + break; +#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 */ +