/*
  シリアル接続制御
  Satofumi KAMIMURA
  Tomoaki YOSHIDA
  $Id: serialDevice_win.cpp 286 2008-10-20 09:40:22Z satofumi $
*/

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


SerialDevice::~SerialDevice(void) {
  raw_disconnect();
}


const char* SerialDevice::what(void) {
  return error_message.c_str();
}


SerialDevice::SerialDevice(int buffer_size)
  : ConnectionDevice(buffer_size), hComm(INVALID_HANDLE_VALUE),
    error_message("Connection device is not specified") {
}


int SerialDevice::raw_connect(const char* device, long baudrate) {
  char comPort[16];
  if (strlen(device) >= 16) {
    return DeviceOpenFail;
  }
  sprintf(comPort, "\\\\.\\%s", device);
  hComm = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
		     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hComm == INVALID_HANDLE_VALUE) {
    LPVOID lpMsg;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
		  FORMAT_MESSAGE_FROM_SYSTEM |
		  FORMAT_MESSAGE_IGNORE_INSERTS,
		  NULL, GetLastError(),
		  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		  (LPTSTR)&lpMsg, 0, NULL);
    printf("port(%s) open failed: %s\n", device, (char *)lpMsg);
    LocalFree(lpMsg);
    return DeviceOpenFail;
  }
  return 0;
}


void SerialDevice::raw_disconnect(void) {
  CloseHandle(hComm);
}


bool SerialDevice::isConnected(void) {
  return (hComm != INVALID_HANDLE_VALUE) ? true : false;
}


int SerialDevice::raw_setBaudrate(long baudrate) {
  DCB dcb;
  GetCommState(hComm, &dcb);
  dcb.BaudRate = baudrate;
  dcb.ByteSize = 8;
  dcb.Parity = NOPARITY;
  dcb.fParity = FALSE;
  dcb.StopBits = ONESTOPBIT;
  SetCommState(hComm, &dcb);

  return 0;
}


int SerialDevice::raw_send(const char* data, int len) {
  DWORD n;
  WriteFile(hComm, data, len, &n, NULL);
  return n;
}


void SerialDevice::raw_flush(void) {
}


void SerialDevice::raw_check(int require_size, long timeout) {
  if (require_size <= 0) {
    return;
  }

  int read_size = require_size;
  if (timeout > 0) {
    COMMTIMEOUTS pcto;
    GetCommTimeouts(hComm, &pcto);
    pcto.ReadIntervalTimeout = 0;
    pcto.ReadTotalTimeoutConstant = timeout;
    pcto.ReadTotalTimeoutMultiplier = 2;
    SetCommTimeouts(hComm, &pcto);

  } else {
    DWORD dwErrors;
    COMSTAT ComStat;
    ClearCommError(hComm, &dwErrors, &ComStat);
    read_size = ((int)ComStat.cbInQue > require_size)
      ? require_size : ComStat.cbInQue;
  }
  char buffer[BufferSize];
  DWORD n;
  ReadFile(hComm, buffer, read_size, &n, NULL);
  recv_buffer->put(buffer, n);
}


#if 0
std::vector<std::string> SerialDevice::getComPorts(void) {
  std::vector<std::string> ports;

  HKEY hkey;
  RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0,
	       KEY_READ, &hkey);

  enum { MaxLength = 32, };
  CHAR device[MaxLength];
  char name[MaxLength];
  DWORD ret = ERROR_SUCCESS;
  for (int i = 0; ret == ERROR_SUCCESS; ++i) {
    DWORD dl = MaxLength, nl = MaxLength;
    ret = RegEnumValue(hkey, i, device, &dl, NULL, NULL, (BYTE*)name, &nl);
    if (ret == ERROR_SUCCESS) {
      ports.push_back(std::string(name));
    }
  }
  RegCloseKey(hkey);

  return ports;
}
#endif
