/*
 *
 * $Id: serialport_ftdi.cpp 2 2008-07-30 09:28:03Z mschneider $
 * $URL: svn://localhost/Bioloid/trunk/serialport_ftdi.cpp $
 
 * \version   $Rev: 2 $
 * \author    Markus Schneider
 * \date      17.07.08
 *
 */

#include "serialport_ftdi.h"
#include <stdio.h>


/* ftdi_usb_open return values:
 0,: 	all fine
-1,: 	usb_find_busses() failed
-2,: 	usb_find_devices() failed
-3,: 	usb device not found
-4,: 	unable to open device
-5,: 	unable to claim device
-6,: 	reset failed
-7,: 	set baudrate failed
-8,: 	get product description failed
-9,: 	get serial number failed
-10,: 	unable to close device
 */

SerialPort_FTDI::SerialPort_FTDI()
{
  int status;
  ftdi_init(&ftdic);
  
  // open the device
  status = ftdi_usb_open(&ftdic, 0x0403, 0x6001);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::SerialPort_FTDI] ftdi_usb_open(%d)\n", status);
    return;
  }     
  
  setupDevice();
}

SerialPort_FTDI::SerialPort_FTDI(int vendor, int product)
{
  int status;
  ftdi_init(&ftdic);
  
  // open the device
  status = ftdi_usb_open(&ftdic, vendor, product);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::SerialPort_FTDI] ftdi_usb_open(%d)\n", status);
    return;
  }    

  setupDevice();
}


int SerialPort_FTDI::setupDevice()
{
  int status;
  
  // perform 1 read/write operation at start. 
  // seems to be a workaround if the port was not
  // correct closed befor.
  unsigned char tmp;
  writeByte(0x0);
  readByte(&tmp);
    
  
  // Set the chip baud rate
  status = ftdi_set_baudrate(&ftdic, 1000000);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::SerialPort_FTDI] ftdi_set_baudrate(%d)\n", status);
    return status;
  }   
  
  // set 8Bits, 1Stop, no parity
  status = ftdi_set_line_property(&ftdic, BITS_8, STOP_BIT_1, NONE);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::SerialPort_FTDI] ftdi_set_line_property(%d)\n", status);
    return status;
  }
  
  // set no flow control
  status = ftdi_setflowctrl(&ftdic, SIO_DISABLE_FLOW_CTRL);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::SerialPort_FTDI] ftdi_setflowctrl(%d)\n", status);
    return status;
  }  
  
  setTimeout(1000);
  
  return 0;
}

/**
 * Set the read/write timeout
 * @param msec Timeout in milliseconds
 * @return  0 on no Error
 */
int SerialPort_FTDI::setTimeout(unsigned int msec)
{
  ftdic.usb_read_timeout = msec;
  ftdic.usb_write_timeout = msec;
  return 0;
}


/**
 * Read data from the device
 * @param RxBuff Buffer to store read data
 * @param RxBytes Number of bytes to read from decice
 * @return Number of bytes read
 */
int SerialPort_FTDI::readData(unsigned char RxBuff[], unsigned int RxBytes)
{
  int status;
  status = ftdi_read_data(&ftdic, RxBuff, RxBytes);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_D2XX::readData] ftdi_read_data(%d)\n", status);
  }    
  return status;
}


/**
 * Read 1 byte from the device
 * @param byte Buffer to store read data
 * @return Number of bytes read
 */
int SerialPort_FTDI::readByte(unsigned char * byte)
{
  int status;
  status = ftdi_read_data(&ftdic, byte, 1);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_D2XX::readData] ftdi_read_data(%d)\n", status);
  }    
  return status;
}


/**
 * Write data to the device
 * @param TxBuff Pointer to the buffer that contains the data to be written to the device
 * @param TxBytes Number of bytes to write to the device
 * @return Number of bytes written
 */
int SerialPort_FTDI::writeData(unsigned char TxBuff[], unsigned int TxBytes)
{
  int status;
  status = ftdi_write_data(&ftdic, TxBuff, TxBytes);  
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_D2XX::writeData] ftdi_write_data(%d)\n", status);
  }    
  return status;  
}

/**
 * Write a byte to the device
 * @param byte The byte to write
 * @return Number of bytes written
 */
int SerialPort_FTDI::writeByte(unsigned char byte)
{
  int status;
  status = ftdi_write_data(&ftdic, &byte, 1);  
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_D2XX::writeData] ftdi_write_data(%d)\n", status);
  }    
  return status;
}

SerialPort_FTDI::~SerialPort_FTDI()
{
  int status = ftdi_usb_close(&ftdic);
  if( status < 0 ){
    fprintf(stderr, "Error [SerialPort_FTDI::~SerialPort_FTDI] ftdi_usb_close(%d)\n", status);
  }   
  
  ftdi_deinit(&ftdic);
}
