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

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


/**
 * Serial port constructor
 * @param iDevice Must be 0 if only one device is attached. For multiple devices 1, 2 etc.
 */
SerialPort_D2XX::SerialPort_D2XX(int iDevice)
{
  FT_STATUS ftStatus;
  ftStatus = FT_Open(iDevice,&ftHandle);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::SerialPort_D2XX] FT_Open(%d)\n", ftStatus);
    return;
  }
  
  ftStatus = setupDevice();
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::SerialPort_D2XX] setupDevice(%d)\n", ftStatus);
    return;
  }
}

/**
 * Serial port constructor
 * @param deviceID The internal decie ID
 */
SerialPort_D2XX::SerialPort_D2XX(char deviceID[])
{
  FT_STATUS ftStatus;
  ftStatus = FT_OpenEx(deviceID, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::SerialPort_D2XX] FT_Open(%d)\n", ftStatus);
    return;
  }
  
  ftStatus = setupDevice();
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::SerialPort_D2XX] setupDevice(%d)\n", ftStatus);
    return;
  }
  
}

/**
 * This will set the device to 1,000,000 Baud, 8Bits, 1Stop, no Parity, no Flow
 * @return The FT_STATU like in ftd2xx.h. 0 on no Error
 */
int SerialPort_D2XX::setupDevice()
{
  FT_STATUS ftStatus;
  
  // reset device
  ftStatus = FT_ResetDevice(ftHandle);
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::setupDevice] FT_ResetDevice(%d)\n", ftStatus);
    return ftStatus;
  }
  
  // Set baudrate
  ftStatus = FT_SetBaudRate(ftHandle, 1000000);
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::setupDevice] FT_SetBaudRate(%d)\n", ftStatus);
    return ftStatus;
  }
  
  // set 8Bits, 1Stop, no Parity
  ftStatus = FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::setupDevice] FT_SetDataCharacteristics(%d)\n", ftStatus);
    return ftStatus;
  }  
  
  // set no flow control
  ftStatus = FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0);
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::setupDevice] FT_SetFlowControl(%d)\n", ftStatus);
    return ftStatus;
  }      
  
  return 0;
}

/**
 * Set the read/write timeout
 * @param msec Timeout in milliseconds
 * @return The FT_STATU like in ftd2xx.h. 0 on no Error
 */
int SerialPort_D2XX::setTimeout(unsigned int msec)
{
  FT_STATUS ftStatus;

  // FT_SetTimeouts(FT_HANDLE ftHandle, DWORD dwReadTimeout, DWORD dwWriteTimeout) 
  ftStatus = FT_SetTimeouts(ftHandle,msec,msec);
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::setTimeout] FT_SetTimeouts(%d)\n", ftStatus);
    return ftStatus;
  } 
  
  return 0;
}

/**
 * resets the device
 */
int SerialPort_D2XX::clear()
{
  FT_STATUS ftStatus;
  DWORD RxBytes; 
  DWORD BytesReceived; 
    
  ftStatus = FT_GetQueueStatus(ftHandle, &RxBytes); 
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::clear] FT_GetQueueStatus(%d)\n", ftStatus);
    return ftStatus;
  }   
   
  char RxBuffer[RxBytes]; 
  ftStatus = FT_Read(ftHandle,RxBuffer,RxBytes,&BytesReceived);  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::clear] FT_Read(%d)\n", ftStatus);
    return ftStatus;
  }     
  
  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_D2XX::readData(unsigned char RxBuff[], unsigned int RxBytes)
{
  FT_STATUS ftStatus;
  DWORD BytesReceived;
  ftStatus = FT_Read(ftHandle,RxBuff,RxBytes,&BytesReceived);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::readData] FT_Read(%d)\n", ftStatus);
    return 0;
  } 
  
  return (int) BytesReceived;
}

/**
 * Read 1 byte from the device
 * @param byte Buffer to store read data
 * @return Number of bytes read
 */
int SerialPort_D2XX::readByte(unsigned char * byte)
{
  FT_STATUS ftStatus;
  DWORD BytesReceived;
  ftStatus = FT_Read(ftHandle,byte,1,&BytesReceived);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::readByte] FT_Read(%d)\n", ftStatus);
    return 0;
  } 
  
  return (int) BytesReceived;
}

/**
 * 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_D2XX::writeData(unsigned char TxBuff[], unsigned int TxBytes)
{
  FT_STATUS ftStatus;
  DWORD BytesWritten;
  ftStatus = FT_Write(ftHandle, TxBuff, TxBytes, &BytesWritten);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::writeData] FT_Write(%d)\n", ftStatus);
    return 0;
  } 
  
  return (int) BytesWritten;
}
  

/**
 * Write a byte to the device
 * @param byte The byte to write
 * @return Number of bytes written
 */
int SerialPort_D2XX::writeByte(unsigned char byte)
{
  FT_STATUS ftStatus;
  DWORD BytesWritten;
  ftStatus = FT_Write(ftHandle, &byte, 1, &BytesWritten);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::writeByte] FT_Write(%d)\n", ftStatus);
    return 0;
  } 
  
  return (int) BytesWritten;
}

/**
 * Closes the serical port
 */
SerialPort_D2XX::~SerialPort_D2XX()
{
  FT_STATUS ftStatus;
  ftStatus = FT_Close(ftHandle);
  
  if( ftStatus != FT_OK ){
    fprintf(stderr, "Error [SerialPort_D2XX::~SerialPor] FT_Close(%d)\n", ftStatus);
  }   
}
