/*
   NXTLeftRightController.c

   Copyright 2006, Sivan Toledo, Tel-Aviv University
 */

#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "user32.lib")

TCHAR *GetLastErrorMessage(DWORD last_error)
{
   static TCHAR errmsg[512];

   if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 
      0,
      last_error,
      0,
      errmsg, 
      511,
      NULL))
   {
      /* if we fail, call ourself to find out why and return that error */
      return (GetLastErrorMessage(GetLastError()));  
   }
  
   return errmsg;
}

void nxt_process_msg(unsigned char* msg) {
  INPUT in;

  printf("Processing message <%s>\n",msg);

  if (strcmp((char*)msg,"RIGHT")==0) {
    in.type = INPUT_KEYBOARD; // INPUT_KEYBOARD
  	in.ki.wVk = VK_RIGHT;
	  in.ki.wScan = 0;
	  in.ki.dwFlags = 0;
	  in.ki.time = 0; // system supplies time stamp
	  in.ki.dwExtraInfo = 0;
	  SendInput(1,&in,sizeof(in));
  }

  if (strcmp((char*)msg,"LEFT")==0) {
    in.type = INPUT_KEYBOARD; // INPUT_KEYBOARD
  	in.ki.wVk = VK_LEFT;
	  in.ki.wScan = 0;
	  in.ki.dwFlags = 0;
	  in.ki.time = 0; // system supplies time stamp
	  in.ki.dwExtraInfo = 0;
	  SendInput(1,&in,sizeof(in));
  }

}

#define DIRECT_COMMAND 0
#define SYSTEM_COMMAND 1
#define REPLY          2

void nxt_bt_read(HANDLE h) {
	unsigned char buffer[256];
	DWORD bytes_received;

  DWORD total = 0;

  /* read the two-byte header containing the length of the message */

  while (total < 2) {
    printf("Calling ReadFile, total so far = %d\n",total);
    if (ReadFile(h, buffer+total, 256, &bytes_received, NULL) == 0) {
      printf("ReadFile error: %s",GetLastErrorMessage(GetLastError()));
      return;
    } else {
      total += bytes_received;
    }
  }

  DWORD packet_length;

  packet_length = buffer[0] + 256*buffer[1]; /* LSB, MSB */
  printf("packet length = %d\n",packet_length);

  while (total < 2+packet_length) {
    printf("Calling ReadFile, total so far = %d\n",total);
    if (ReadFile(h, buffer + total, 256, &bytes_received,NULL) == 0) {
      printf("ReadFile error: %s",GetLastErrorMessage(GetLastError()));
      return;
    } else {
      total += bytes_received;
    }
  }

  printf("done reading the packet, analyzing it now\n");

  unsigned char type, reply_requested, command, msg_size, inbox;
  unsigned char* msg;

  switch (buffer[2]) { /* packet type */
    case 0x00: 
      type            = DIRECT_COMMAND;
      reply_requested = 1;
      break;
    case 0x01: 
      type            = SYSTEM_COMMAND;
      reply_requested = 1;
      break;
    case 0x02: 
      type            = REPLY;
      reply_requested = 0;
      break;
    case 0x80: 
      type            = DIRECT_COMMAND;
      reply_requested = 0;
      break;
    case 0x81: 
      type            = SYSTEM_COMMAND;
      reply_requested = 0;
      break;
  }    

  switch (buffer[3]) { /* command */
    case 0x09:
      inbox    = buffer[4];
      msg_size = buffer[5];
      msg      = buffer+6;
      nxt_process_msg(msg);
      break;
  }
}

int main(int argc, char* argv[])
{
  if (argc < 2) {
    printf("usage: %s COM?\n",argv[0]);
    printf("       where ? is the port number of the bluetooth serial port\n");
    printf("       when this computer is used as a bluetooth client.\n");
    printf("       To find out the port number, right click on the bluetooth icon\n");
    printf("       in the tray, select Advanced Configuration, select the Local Services\n");
    printf("       tab, and note the COM port of the serial service.\n");
    printf("       \n");
    printf("       When used with an appropriate NXT program, the NXT is used as a two-key\n");
    printf("       keyboard, with the keys LEFT and RIGHT.\n");
    printf("       \n");
    printf("       On the NXT side, pair with the PC (initiate the pairing from the NXT)\n");
    printf("       and run a program that sends the strings LEFT and RIGHT when you click.\n");
    printf("       on the buttons.\n");
    exit(0);
  }

	HANDLE h;
	DCB config_;

  char  port_name[256];
  strcpy(port_name,"//./");
  strcat(port_name,argv[1]);

	h = CreateFile(port_name,  // Specify port device: default "COM1"
	               GENERIC_READ | GENERIC_WRITE,       // Specify mode that open device.
                 0,                                  // the devide isn't shared.
                 NULL,                               // the object gets a default security.
                 OPEN_EXISTING,                      // Specify which action to take on file. 
                 0,                                  // default.
                 NULL);                              // default.

	if (h == INVALID_HANDLE_VALUE) {
		printf("failed to open COM port <%s>: %s", port_name, GetLastErrorMessage(GetLastError()));
		return -1;
	}

  if (GetCommState(h,&config_) == 0) {
		printf("GetCommState error: %s",GetLastErrorMessage(GetLastError()));
    return -1;
  }

  COMMTIMEOUTS comTimeOut;                   
  GetCommTimeouts(h,&comTimeOut);
  printf("read interval timeout   = %d\n",comTimeOut.ReadIntervalTimeout);
  printf("read multiplier timeout = %d\n",comTimeOut.ReadTotalTimeoutMultiplier);
  printf("read constant timeout   = %d\n",comTimeOut.ReadTotalTimeoutConstant);

  comTimeOut.ReadIntervalTimeout         = 3;
  comTimeOut.ReadTotalTimeoutMultiplier  = 3;
  comTimeOut.ReadTotalTimeoutConstant    = 60000;
  comTimeOut.WriteTotalTimeoutMultiplier = 0;
  comTimeOut.WriteTotalTimeoutConstant   = 0;

  SetCommTimeouts(h,&comTimeOut);

	while (1) {
    nxt_bt_read(h);
	}

  if (CloseHandle(h) == 0) {
    return -1;
  }

	return 0;
}

