// Filename: external/TSerial.cpp
// Author: Jorge Bernadas (JB)
// Date of Creation: 11/02/2007
// Version: 1.0
/*#include "base/General.h"
#include "base/Check.h"
#include "external/TSerial.h"
*/
#include "TSerial.h"
#include "../Base/LogManagement.h"

BEGIN_TEG_NAMESPACE();
//BEGIN_ENGINE_NAMESPACE();
//BEGIN_ENGINE_SUB_NAMESPACE(ext);
namespace ext {

// initialize all values with 0
TSerial::TSerial() : baudrate_(0), parity_(NO_PARITY), handle_(INVALID_HANDLE_VALUE) {
  _tcscpy(port_, _T(""));
}

TSerial::~TSerial() {
  Disconnect();
}

bool TSerial::Connect(const _TCHAR* port, int baudrate, SerialParity parity) {
  // initialize and check input arguments
  Disconnect();
  //CHECK(port != NULL, _T("Cannot open connection with serial port ")
  //  _T("using a NULL port name"));
  if (port == NULL) {
    PRINT_LOG(TYPE_WARNING, _T("Cannot open connection with serial port using a NULL port name."));
    return false;
  }

  // store attributes in the serial port
  _tcsncpy(port_, port, kMaxPortNameLength);
  port_[kMaxPortNameLength - 1] = _T('\0');
  baudrate_ = baudrate;
  parity_ = parity;

  // initialize DCB to configure the serial port
  DCB dcb;
  memset(&dcb, 0, sizeof(dcb));
  dcb.DCBlength = sizeof(dcb);                   
  dcb.BaudRate = baudrate;
  dcb.fBinary = TRUE;
  dcb.fParity = parity != NO_PARITY ? TRUE : FALSE;
  dcb.fOutxCtsFlow = FALSE;
  dcb.fOutxDsrFlow = FALSE;
  dcb.fDtrControl = DTR_CONTROL_DISABLE;
  dcb.fDsrSensitivity = FALSE;
  dcb.fTXContinueOnXoff = FALSE;
  dcb.fOutX = FALSE;
  dcb.fInX = FALSE;
  dcb.fErrorChar = FALSE;
  dcb.fNull = FALSE;
  dcb.fRtsControl = RTS_CONTROL_DISABLE;
  dcb.fAbortOnError = FALSE;
  dcb.XonLim = 2;
  dcb.XoffLim = 4;
  dcb.ByteSize = 8;
  dcb.Parity = static_cast<int>(parity);
  dcb.StopBits = ONESTOPBIT;
  dcb.XonChar = 0x13;
  dcb.XoffChar = 0x19;
  dcb.ErrorChar = '\\';
  dcb.EofChar = '\\';
  dcb.EvtChar = 0;

  // open serial port file and check if it was opened
  handle_ = ::CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
  //CHECK(handle_ != INVALID_HANDLE_VALUE, _T("Error while trying to open serial ")
  //  _T("port \"%s\" with baudrate %d.\n"), port, baudrate);
  if (handle_ == INVALID_HANDLE_VALUE) {
    PRINT_LOG(TYPE_WARNING, _T("Error while trying to open serial port \"%s\" with baudrate %d."), port, baudrate);
	return false;
  }

  // set event mask, timeouts and DCB state
  //CHECK(SetCommMask(handle_, 0), _T("Error while setting serial port event mask to 0.\n"))
  if (!SetCommMask(handle_, 0)) {
    PRINT_LOG(TYPE_WARNING, _T("Error while setting serial port event mask to 0."));
	return false;
  }
  COMMTIMEOUTS cto = {0, 0, 0, 0, 0};
  //CHECK(SetCommTimeouts(handle_, &cto), _T("Error while setting serial port timeouts.\n"))
  //CHECK(SetCommState(handle_, &dcb), _T("Error while setting serial port DCB state.\n"));
  if (!SetCommTimeouts(handle_, &cto)) {
    PRINT_LOG(TYPE_WARNING, _T("Error while setting serial port timeouts."));
	return false;
  }
  if (!SetCommState(handle_, &dcb)) {
    PRINT_LOG(TYPE_WARNING, _T("Error while setting serial port DCB state."));
	return false;
  }
  return true;
}

void TSerial::Disconnect() {
  // close handle and reset it
  if (handle_ != INVALID_HANDLE_VALUE)
    ::CloseHandle(handle_);
  handle_ = INVALID_HANDLE_VALUE;
}

int TSerial::SendArray(const char *buffer, int count) {
  // write the array and return the number of bytes written
  DWORD writeCount = 0;
  if (handle_ != INVALID_HANDLE_VALUE)
    ::WriteFile(handle_, buffer, count, &writeCount, NULL);
  return static_cast<int>(writeCount);
}

int TSerial::GetArray(char* buffer, int count) {
  // read data from the serial port if the file is open
  DWORD readCount = 0;
  if (handle_ != INVALID_HANDLE_VALUE)
    ::ReadFile(handle_, buffer, count, &readCount, NULL);
  return static_cast<int>(readCount);
}

int TSerial::GetAvailableBytes() {
  // get the port status and return the number of bytes in queue
  _COMSTAT status;
  int byteCount = 0;
  if (handle_ != INVALID_HANDLE_VALUE) {
    DWORD etat = 0;
    ::ClearCommError(handle_, &etat, &status);
    byteCount = status.cbInQue;
  }
  return byteCount;
}

}; // Namespace ext
//END_ENGINE_SUB_NAMESPACE(ext);
//END_ENGINE_NAMESPACE();
END_TEG_NAMESPACE();
