/*
			 Siemens AG
		 Mobile Radio Terminals
		  Munich, Germany

.AUTHOR         J.Packeiser

.VERSION        1.1

.DATE           22.04.2004

.SHORT_DESCR    

.SW_COMPONENT   

.SW_TYPE        

.STATUS         INOFFICAL

.CHANGE_CONTROL
Version |  Date  | Changed by  | Reason for Change
  0.1    16.04.02  J.Packeiser   file created
  0.2	 19.04.02  J.Packeiser     created dialog
  0.3	 03.05.02  J.Packeiser     inserted optical upgrades
  0.4    22.05.02  J.Packeiser	moved some functions to irpcmmi.c
  0.5    17.06.02  J.Packeiser	added Functions for IrdA Traces
  0.6    03.09.02  J.Packeiser   OpenFile Dialog added
  0.7    13.09.02  J.Packeiser   CloseCOM: PurgeComm before while-thread halted
  0.8    03.09.03  A. Bucher     changes for MOPI...\n
                                 restructured OVERLAPPED operation\n 
                                 interface changed (include irmsg.h removed -> Frame passed as unsigned char* )\n
  0.9    27.11.03  A. Bucher     call to IrDA_vSwitchOnReq removed\n
  1.0    18.03.04  A. Bucher     Storing/reading ComPort and Dongletype to/from registry\n
                                 adapting length of some character arrays\n
                                 -> CQ DT100005601 and DT100005569 bugfix
  1.1    24.04.04  A. Bucher     uiBaudNr now initialised in ReadIrPCMMIRegistrySetting
                 
*/

#define MAXCOM 21

#define REG_COMPORT  "IrDAComPort"
#define REG_DONGLE   "IrDADongleType"

extern "C" 
{
	#include <global.h>
}

#include <stdio.h>				// needed for sprintf
#include "winmain.h"			   // needed for windows functions (DispGetWinHandle, ...)
#include "winrc.h"				// needed for Callback function messages
#include "mopi.h"
#include "mopiext.h"
#include "sim_regh.h"

extern "C" 
{
#include "vcdbgout.h"  //debug out
}

// Datatypes
typedef enum {XID, SNRM, ACTIVATE, DEACTIVATE, STORE_COM, STORE_DONGLE, STOP, CREATED_FILE, REPLACED_FILE, DONT_REPLACE_FILE} TYP;
typedef enum {ESI, PAR} DONG;
typedef enum {NO_CHANGES, SUCCEEDED, FAILED} COMRET;
unsigned char ucXIDFrame[]={0xc0, 0xff, 0x3f, 0x01, 0xcf, 0x0f, 0x00, 0x00,
							       0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x0c,
				 			       0x28, 0xc1};


//externals
extern "C" HWND DispGetWinHandle(void);		// Windows function

// externals in irpcmmi.c
extern "C" void IrDASerComRead(BYTE);		// function in irpcmmi.c

// defined as C function
extern "C" void SetSpeed(unsigned long);	// called from irpcmmi.c
extern "C" void IrDA_Init(void);
extern "C" void WriteIrDATrace(char*, unsigned char *, unsigned int, unsigned int);	// called from irpcmmi.c
extern "C" BOOL InitialiseIrDAPCMMI(void);                                          // called from irpcmmi.c
extern "C" void DeactivateIrDAPCMMI(void);                                          // called from irpcmmi.c


// internals
void initWindow(HWND, UINT, UINT, char *);
BOOL InitCom (unsigned int, unsigned int); //, HWND);
BOOL CloseCom(void);

extern "C" void SendIrDAFrame(unsigned char *, unsigned int Length);
extern "C" void ShowSentFrames(void);
BOOL SendTestFrame(UINT);
DWORD dwWatchSerComIrDA(void);
void ScrollTextField(void);
void ShowMsg(BOOL, TYP);


// Globals
HWND hIrDADialog, hwndGlob;
static HANDLE hCom=INVALID_HANDLE_VALUE, hReadThread=NULL;
static volatile DWORD dwThreadID;
static volatile BOOL bStopThread = FALSE, bIsChanging=FALSE;
static OVERLAPPED stOverlapedWrite;
static OVERLAPPED stOverlapedRead;
static char cpath[MAX_PATH];
static DONG dDongle=PAR;
static BOOL bTraceIrDA=FALSE;
static char sWindowMsg[1000];
static BOOL bIrDAisAct=FALSE;
static UINT uiComNr=1;
static UINT uiBaudNr=2;
static UINT uiFrameNr=0;

// TBD
void __cdecl report_failure(int code, void * unused)
{
    if (code == _SECERR_BUFFER_OVERRUN)
      printf("Buffer overrun detected!\n");
}



BOOL ReadIrPCMMIRegistrySetting(void)
{
   int resultCom, resultDongle;

   uiComNr = ReadSimulatorRegistry(REG_COMPORT, &resultCom);
   dDongle = (DONG)ReadSimulatorRegistry(REG_DONGLE, &resultDongle);
   if ((0 != resultDongle) || (0 != resultCom))
   {
      uiComNr = 0;
      dDongle = PAR;
      uiBaudNr = 2;  // 9600 baud
      MessageBox(DispGetWinHandle(), "Using COM1 and Parallax dongle as default", "Error reading registry", MB_OK|MB_ICONEXCLAMATION);
	  // store default settings in registry
  	  if (0 == WritePermanentSimulatorRegistry(REG_COMPORT, uiComNr))
	  {
	  	  ShowMsg(TRUE,STORE_COM);
	  }
  	  if (0 == WritePermanentSimulatorRegistry(REG_DONGLE, dDongle))
	  {
	  	  ShowMsg(TRUE,STORE_DONGLE);
	  }
      return FALSE;
   }
	// initialise uiBaudNr
	if (PAR == dDongle)
	{
		uiBaudNr = 2;  // 9600 baud
	}
	else  // XTNDAccess
	{
		uiBaudNr = 0;  // 9600 baud
	}
   return TRUE;
}


static void DisplayLastError(HWND hwnd, DWORD dwLastError)
{
   LPVOID lpMsgBuf;

   (void)FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                       NULL,
                       dwLastError,   // GetLastError(),
                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                       (LPTSTR) &lpMsgBuf,
                       0,
                       NULL);
   // Display the string.
   (void)MessageBox(hwnd, (LPCSTR)lpMsgBuf, TEXT("GetLastError"), MB_OK|MB_ICONINFORMATION );

   // Free the buffer.
   (void)LocalFree( lpMsgBuf );
}




/* ----------------------------------------------------------------------------*/
/** 
@short Suspends Windows Rx thread

   Declared as C function as called from irpcmmi.c
*/
/* ----------------------------------------------------------------------------*/
extern "C" void IrDASuspendRxThread(void)
{
   if ((DWORD)-1 == SuspendThread(hReadThread))
   {
      DisplayLastError(DispGetWinHandle(), GetLastError());
   }
}


/* ----------------------------------------------------------------------------*/
/** 
@short Resumes Windows Rx thread

   Declared as C function as called from irpcmmi.c
*/
/* ----------------------------------------------------------------------------*/
extern "C" void IrDAResumeRxThread(void)
{
   if ((DWORD)-1 == ResumeThread(hReadThread))
   {
      DisplayLastError(DispGetWinHandle(), GetLastError());
   }
}


//////////////////////////////////////////////////////////////////////
BOOL CALLBACK IrDADialogProc(HWND hwndDlg, UINT message, WPARAM wParam, 
							        LPARAM lParam)
//////////////////////////////////////////////////////////////////////
{
	static char cMsg[1000];
	static BOOL bInAlr=FALSE;
	char cFileName[256];
	/* File open Logfile */
	static OPENFILENAME lpfile;
	char cFilter[33]={"IrDA trace files (*.itf)\0*.itf\0\0"};

	hwndGlob=hwndDlg;

	switch (message)
	{
   	case WM_INITDIALOG:
		{
         _set_security_error_handler(report_failure);  // TBD
         SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_ACT), (UINT) WM_SETTEXT, (WPARAM) 0, (WPARAM)"Store");
         EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_DEACT),FALSE); 

         ReadIrPCMMIRegistrySetting();
         initWindow(hwndDlg, uiComNr, uiFrameNr, cMsg);
         return TRUE;
		}

   	case WM_CLOSE:
		{
			DestroyWindow(hwndDlg);
			hIrDADialog = 0;
			return TRUE;
		}
	
      case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
			   case IDC_IrDA_ACT:		// click on Button "Store"
				   // -----  get selected Settings -----
				   uiComNr=SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_COM), 
				                       CB_GETCURSEL, 0, 0);

               /*
               AB 12.09.2003 removed as you always must start with 9600 Baud
               uiBaudNr=SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_GETCURSEL, 0, 0);
               */

   //				EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_PAR),FALSE); 
   //				EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_ESI),FALSE);

               if (0 == WritePermanentSimulatorRegistry(REG_COMPORT, uiComNr))
               {
                  ShowMsg(TRUE,STORE_COM);
               }

               if (0 == WritePermanentSimulatorRegistry(REG_DONGLE, dDongle))
               {
                  ShowMsg(TRUE,STORE_DONGLE);
               }
               return TRUE;

			   case IDC_IrDA_DEACT:
				   EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_PAR),TRUE); 
				   EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_ESI),TRUE);
   				
				   return TRUE;

			   case IDC_IrDA_TESTFR:		// click on Button Send Test Frame
				   if(hCom != INVALID_HANDLE_VALUE)
				   {
					   uiFrameNr=SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_FRAME),
						   CB_GETCURSEL, 0, 0);

				   // -----  Showing what is done -----
					   ShowMsg(SendTestFrame(uiFrameNr), XID);

					   return TRUE;
				   }

			   case IDC_IrDA_PAR:
				   if (PAR == dDongle)
					   return TRUE;
				   dDongle=PAR;
               uiBaudNr = 2;  // 9600 baud
               return TRUE;
   /*
   // Bucher 2004-01-14
				   // Delete all Items of Combo Box with Baudrates
				   for(i=1;i<4;i++)
				   {
					   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
						   CB_DELETESTRING, 0, 0);
				   }
				   //Fill in new items
				   for ( i=1; i<8; i++)
				   {
					   sprintf(cComNames, "%d", uiBaud);
					   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
						   CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) cComNames);
					   if (uiBaud==38400)
						   uiBaud=57600;
					   else
						   uiBaud*=2;
				   }
				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_SETCURSEL, uiBaudNr, 0);
   */

			   case IDC_IrDA_ESI:
				   if (ESI == dDongle)
					   return TRUE;
				   dDongle=ESI;
               uiBaudNr = 0;  // 9600 baud
               return TRUE;
   /*
   // Bucher 2004-01-14
               // Delete all Items of Combo Box with Baudrates
				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_SETCURSEL, -1, 0);
				   for(i=0;i<8;i++)
				   {
					   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
						   CB_DELETESTRING, 0, 0);
				   }
				   // Fill in new items
				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "9600");
				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "19200");
				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "115200");

				   SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
					   CB_SETCURSEL, 0, 0);
   */

            case IDC_IrDA_CHTR:
				   if (bTraceIrDA==FALSE)
				   {
					   bTraceIrDA=TRUE;
					   /* File dialog */
					   lpfile.lStructSize=sizeof(OPENFILENAME);
					   lpfile.hwndOwner=hwndDlg;
					   /* Filter */
					   lpfile.lpstrFilter=cFilter;
					   lpfile.lpstrCustomFilter=NULL;
					   lpfile.nFilterIndex=0;

					   lpfile.lpstrTitle="Logfile";
					   lpfile.lpstrDefExt=".itf";
					   strcpy(cFileName,"");
					   lpfile.lpstrFile=cFileName;
					   lpfile.nMaxFile=255;
					   if(GetSaveFileName(&lpfile)!=0)
					   {
						   WriteIrDATrace(cFileName, NULLP, 0, 0);
					   }
					   else
					   {
						   bTraceIrDA=FALSE;
						   CheckDlgButton(hwndGlob, IDC_IrDA_CHTR, BST_UNCHECKED);
					   }

				   }
				   else
				   {
					   bTraceIrDA=FALSE;
				   }
				   return TRUE;

			   default:
				   return (FALSE);
			}
		}
	}
	return FALSE; 
}

/////////////////////////////////////////////////////////////////////
void initWindow(HWND hwndDlg, UINT uiComNr, 
				    UINT uiFrameNr, char *pcMsg)
/////////////////////////////////////////////////////////////////////
{
	unsigned int i;  
	char cComNames[128];

	// Init Option Buttons
	if (PAR == dDongle)
   {
		CheckDlgButton(hwndDlg, IDC_IrDA_PAR, BST_CHECKED);
   }
	else  // XTNDAccess
   {
		CheckDlgButton(hwndDlg, IDC_IrDA_ESI, BST_CHECKED);
   }
	// Init Check Button ("Trace IrDA Frames")
	if (bTraceIrDA==TRUE)
	{
		CheckDlgButton(hwndDlg, IDC_IrDA_CHTR, BST_CHECKED);
	}
	else
	{
		CheckDlgButton(hwndDlg, IDC_IrDA_CHTR, BST_UNCHECKED);
	}

	// Init the Combobox for the Comports
	for ( i=1; i<MAXCOM; i++)
	{
		sprintf(cComNames, "COM%d", i);
		SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_COM), 
			CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) cComNames);
	}
	SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_COM), 
		         CB_SETCURSEL, uiComNr, 0);

	// Init the Combobox for the Baudrate
   // AB 12.09.2003 Removed as it is confusing to change the baudrate.
   // You must always start with 9600 Baud!!!
	EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), FALSE);
/*	for ( i=1; i<8; i++)
	{
		sprintf(cComNames, "%d", uiBaud);
		SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
			CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) cComNames);
		if (uiBaud==38400)
			uiBaud=57600;
		else
			uiBaud*=2;
	}
	SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_BAUD), 
		CB_SETCURSEL, uiBaudNr, 0);
*/

   // Init the Combobox for Test Frames
	SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_FRAME), 
			CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "XID");
	SendMessage(GetDlgItem(hwndDlg, IDC_IrDA_FRAME), 
			CB_SETCURSEL, uiFrameNr, 0);

	// Init the Text Box
	SetDlgItemText(hwndDlg, IDC_IrDA_TEXT, pcMsg);
	ScrollTextField();
	// Enable Buttons if necessary
	if (hCom!=INVALID_HANDLE_VALUE)
	{
		EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_FRAME),TRUE); 
		EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_TESTFR),TRUE);
	}
}

//////////////////////////////////////////////////////////////////////
BOOL InitCom(unsigned int uiComNr, unsigned int uiBaudNr) 
//////////////////////////////////////////////////////////////////////
{
	int i=0;
	char cComNr[128], cErrorMsg[128];
	ULONG uiSpeed;
	static  DWORD dwCreationFlags = 0;

	stOverlapedWrite.Offset = 0 ;
	stOverlapedWrite.OffsetHigh = 0 ;
	stOverlapedRead.Offset = 0 ;
	stOverlapedRead.OffsetHigh = 0 ;

	// create I/O event used for overlapped reads / writes
	stOverlapedRead.hEvent = CreateEvent( NULL,    // no security
                                        TRUE,    // explicit reset req
                                        FALSE,   // initial event reset
                                        NULL ) ; // no name
#ifdef I_DEBUG
   DbgOut("Created IrDA stOverlapedRead.hEvent 0x%08x",stOverlapedRead.hEvent);
#endif

	stOverlapedWrite.hEvent = CreateEvent( NULL,    // no security
                                         TRUE,    // explicit reset req
                                         FALSE,   // initial event reset
                                         NULL ) ; // no name
#ifdef I_DEBUG
   DbgOut("Created IrDA stOverlapedWrite.hEvent 0x%08x",stOverlapedWrite.hEvent);
#endif

   while (i<2)
	{
#ifdef I_DEBUG
      DbgOut("Closing IrDA port 0x%08x",hCom);
#endif
		CloseHandle(hCom);

		// ---------  get Speed out of CurSel  ---------
		if (PAR == dDongle)
		{
			switch (uiBaudNr)
			{
			case 0: uiSpeed=2400; break;
			case 1: uiSpeed=4800; break;
			case 2: uiSpeed=9600; break;
			case 3: uiSpeed=19200; break;
			case 4: uiSpeed=38400; break;
			case 5: uiSpeed=57600; break;
			case 6: uiSpeed=115200; break;
			}
		}
		else
		{
			switch(uiBaudNr)
			{
			case 0: uiSpeed=9600; break;
			case 1: uiSpeed=19200; break;
			case 2: uiSpeed=115200; break;
			}
		}
	   // ---------  Open chosen Port  ---------
		sprintf(cComNr, "COM%d:",uiComNr);
      hCom =	CreateFile(cComNr,
				GENERIC_READ | GENERIC_WRITE,
				0, 
				NULL, 
				OPEN_EXISTING,
				FILE_FLAG_OVERLAPPED,
				0);
#ifdef I_DEBUG
      DbgOut("Opened IrDA port 0x%08x",hCom);
#endif

		if(hCom == INVALID_HANDLE_VALUE)	// CreateFile failed
		{
			// Error message
			sprintf(cErrorMsg,"Unable to open COM%d: port", uiComNr);
			MessageBox (DispGetWinHandle(),cErrorMsg, NULL, MB_ICONERROR);
			// -----  Disable Buttons -----
//			EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_FRAME),FALSE); 
//			EnableWindow(GetDlgItem(hwndDlg, IDC_IrDA_TESTFR),FALSE);
			return FALSE;
		}

	   // ---------  New Settings ----------
		SetSpeed(uiSpeed);
		i++;
	}

   // -----  Creating Thread -----
	// create prosess dwWatchSerCom()
	bStopThread = FALSE;
	hReadThread = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 
                              0,
                              (LPTHREAD_START_ROUTINE) dwWatchSerComIrDA,
                              0, 
                              dwCreationFlags, 
                              (LPDWORD)&dwThreadID);
	if ( NULL == hReadThread)
	{
		CloseHandle(hReadThread);
		MessageBox (DispGetWinHandle(),"Unable to create the read thread", NULL, MB_ICONERROR);
		
		return FALSE;
	}
	SetThreadPriority(hReadThread, THREAD_PRIORITY_NORMAL/*THREAD_PRIORITY_TIME_CRITICAL*/ );
	return TRUE;
}

/////////////////////////////////////////////////////////////////////
BOOL CloseCom(void)
/////////////////////////////////////////////////////////////////////
{
	if(hCom != INVALID_HANDLE_VALUE)
	{
		// set stop-connected flag to TRUE
		bStopThread = TRUE;
      DbgOut("Stopped IrDA read thread");
  
		// disable event notification and wait for thread to halt
		SetCommMask( hCom, 0 );

      // purge any outstanding reads/writes 
		PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT |
                       PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

		// block until thread has been halted
		while( dwThreadID!=0 );

    	// close device handle
#ifdef I_DEBUG
      DbgOut("Closing IrDA port 0x%08x",hCom);
#endif
		CloseHandle( hCom ) ;
		hCom=INVALID_HANDLE_VALUE;

		// clean up event objects
#ifdef I_DEBUG
      DbgOut("Closing IrDA stOverlapedRead.hEvent 0x%08x",stOverlapedRead.hEvent);
#endif
		CloseHandle( stOverlapedRead.hEvent ) ;
#ifdef I_DEBUG
      DbgOut("Closing IrDA stOverlapedWrite.hEvent 0x%08x",stOverlapedWrite.hEvent);
#endif
      CloseHandle( stOverlapedWrite.hEvent ) ;

		EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_FRAME),FALSE); 
		EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_TESTFR),FALSE);

		return TRUE;
	}
	else 
   {
		return FALSE;
   }
}

/////////////////////////////////////////////////////////////////////
DWORD dwWatchSerComIrDA(void)
/////////////////////////////////////////////////////////////////////
{
	BYTE Byte;
	BOOL fReadStat=TRUE;
	static BOOL bEscaped=FALSE;
	DWORD dwCommModemStatus, dwBytesTransferred, dwErrorFlags;
	COMSTAT ComStat;
	char mess[128];
	static int anz=0;
   DWORD dwError;
  
   // ---------------------------------------------
	// Specify a set of events to be monitored for the port.
	SetCommMask (hCom, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
	
	while (!bStopThread) 
	{
		dwCommModemStatus = 0 ;
		// Wait for an event to occur for the port.
		WaitCommEvent(hCom, &dwCommModemStatus, NULL);
		// Re-specify the set of events to be monitored for the port.
		if( SetCommMask (hCom, EV_RXCHAR) )			
		{	
			// wenn ein Zeichen empfangen wurde
			if (dwCommModemStatus & EV_RXCHAR) 
			{
				if (TRUE == bIsChanging)
            {
					MessageBox (DispGetWinHandle(),"Baudrate is changing at the moment!", NULL, MB_ICONERROR);
            }

				// Loop for waiting for the data stream.
      		do																										
				{
               if (bStopThread)
               {
#ifdef I_DEBUG
                  DbgOut("IrDA: bStopThread 1");
#endif
                  break;
               }
					// Liest ein Byte aus dem Buffer
					fReadStat = ReadFile(hCom, &Byte, 1, &dwBytesTransferred, &stOverlapedRead);			
					if (0 == fReadStat)
					{
                  if (GetLastError() == ERROR_IO_PENDING)
                  {
                     // We have to wait for read to complete.
                     // This function will timeout according to the
                     // CommTimeOuts.ReadTotalTimeoutConstant variable
                     // Every time it times out, check for port errors
                     while(!GetOverlappedResult(hCom, &stOverlapedRead, &dwBytesTransferred, TRUE ))
                     {
                        dwError = GetLastError();
                        if (ERROR_IO_INCOMPLETE == dwError)
                        {	
                           // Overlapped I/O event is not in a signaled state.
                           continue;
                        }
                        else if (ERROR_OPERATION_ABORTED == dwError)
                        {
                           //  The I/O operation has been aborted because of either a thread exit or an application request.
                           dwBytesTransferred = 0 ;
                           break;
                        }
                        else
                        {	// an error occurred, try to recover
                           dwBytesTransferred = 0 ;
                           ClearCommError(hCom, &dwErrorFlags, &ComStat) ;
                           DisplayLastError(DispGetWinHandle(),dwError);
                           break;
                        }
                     }
                  }
                  else
                  {	// some other error occurred
                     DisplayLastError(DispGetWinHandle(), GetLastError());
                     dwBytesTransferred = 0 ;
                     ClearCommError(hCom, &dwErrorFlags, &ComStat) ;
                  }
					}

               if (bStopThread)
               {
#ifdef I_DEBUG
                  DbgOut("IrDA: bStopThread 2");
#endif
                  break;
               }
	
					if (0 != dwBytesTransferred)
					{
						IrDASerComRead(Byte);
						if ((Byte==0xc1)&&(bEscaped==FALSE))
						{
							anz++;
							sprintf(mess,"Received Frames: %d",anz);
							SetDlgItemText(hwndGlob,IDC_IrDA_COUNT,mess);

						}
						if(bEscaped==TRUE)
							bEscaped=FALSE;

						if ((Byte==0x7d)&&(bEscaped==FALSE))
							bEscaped=TRUE;
					}

				} while (0 != dwBytesTransferred);
			} // end of "if (dwCommModemStatus & EV_RXCHAR)"
	
		} // end of "if( SetCommMask (hCom, EV_RXCHAR) )"			

	} // end of "while (!bStopThread)" 

  
  // --------------------------------------------

	// clear flags
   DbgOut("IrDA: leaving thread 0x%08X", dwThreadID);

	CloseHandle(hReadThread);
	dwThreadID=0;

	return 0;
}

/////////////////////////////////////////////////////////////////////
BOOL SendTestFrame(UINT uiFrameNr)
/////////////////////////////////////////////////////////////////////
{
	switch (uiFrameNr)
	{
	   case 0: 
		   SendIrDAFrame(ucXIDFrame, sizeof(ucXIDFrame));
		   return TRUE;

	   default:
		   return FALSE;
	}
}

//////////////////////////////////////////////////////////////////////
void ShowMsg(BOOL bError, TYP tMsg)
//////////////////////////////////////////////////////////////////////
{
#define MSG_SIZE 1000
#define HELP_SIZE 128
	char cMsg[MSG_SIZE], cHelp[HELP_SIZE], cHelp2[HELP_SIZE], cMsg2[HELP_SIZE];
	
	GetDlgItemText(hwndGlob, IDC_IrDA_TEXT, cMsg, MSG_SIZE);
	if (strlen(cMsg)!=0)
	{
		sprintf(cHelp,"%c%c",0x0d, 0x0a);
		strcat(cMsg,cHelp);
	}

	if (bError==FALSE)
	{
		strcat(cMsg,"Error: ");
		sprintf(sWindowMsg,"Error: ");
	}

	switch (tMsg)
	{
	   case ACTIVATE:
		   strcat(cMsg,"Activated Port COM");
		   sprintf(cHelp,"%d with 9600 baud", uiComNr+1); 
		   strcat(cMsg,cHelp);
		   GetDlgItemText(hwndGlob, IDC_IrDA_BAUD, cHelp2, HELP_SIZE);
		   strcat(cMsg, cHelp2);
		   if (bError==TRUE)
		   {
			   EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_FRAME),TRUE); 
			   EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_TESTFR),TRUE);
		   }

		   strcat(sWindowMsg,"Activated Port COM");
		   strcat(sWindowMsg,cHelp);
		   strcat(sWindowMsg,cHelp2);
		   break;

	   case DEACTIVATE:
		   strcat(cMsg, "Deactivated Port");
		   EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_FRAME),FALSE); 
		   EnableWindow(GetDlgItem(hwndGlob, IDC_IrDA_TESTFR),FALSE);
   		
		   strcat(sWindowMsg,"Deactivated Port");
		   break;

	   case XID: 
		   strcat(cMsg, "Sent Test Frame (XID)");
   		
		   strcat(sWindowMsg,"Sent Test Frame (XID)");
		   break;

	   case STORE_COM:
		   strcat(cMsg,"Stored COM port setting in Registry");
   		
		   strcat(sWindowMsg,"Stored COM port setting in Registry");
		   break;
	   case STORE_DONGLE:
		   strcat(cMsg,"Stored dongle setting in Registry");
   		
		   strcat(sWindowMsg,"Stored dongle setting in Registry");
		   break;
	   case CREATED_FILE:
		   sprintf(cMsg2,"Created file:  %s", cpath);
		   strcat(cMsg,cMsg2);

		   strcat(sWindowMsg,cMsg2);
		   break;
	   case REPLACED_FILE:
		   sprintf(cMsg2,"Replaced file:  %s", cpath);
		   strcat(cMsg,cMsg2);

		   strcat(sWindowMsg,cMsg2);
		   break;
	   case DONT_REPLACE_FILE:
		   sprintf(cMsg2,"Didn't replace file:  %s", cpath);
		   strcat(cMsg,cMsg2);

		   strcat(sWindowMsg,cMsg2);
		   break;
	}

	WriteIrDATrace(NULL, NULL, 0, 3);

	SetDlgItemText(hwndGlob, IDC_IrDA_TEXT, cMsg);
	ScrollTextField();
}


void ShowSentFrames(void)
{
	static int anz=0;
	char mess[128];

	anz++;
	sprintf(mess,"Sent Frames: %d",anz);
	SetDlgItemText(hwndGlob,IDC_IrDA_COUNTGOOUT,mess);
}


//////////////////////////////////////////////////////////////////////
void ScrollTextField(void)
//////////////////////////////////////////////////////////////////////
{
	UINT uiNum;

	uiNum=SendMessage(GetDlgItem(hwndGlob, IDC_IrDA_TEXT),
		EM_GETLINECOUNT,0,0);
	SendMessage(GetDlgItem(hwndGlob, IDC_IrDA_TEXT),
		EM_LINESCROLL,0,uiNum-3);
}


/////////////////////////////////////////////////////////////////////
void open_IrDA_command_dialog( void )
/////////////////////////////////////////////////////////////////////
{
	if(hIrDADialog != NULL)
	{
		return;
	}
	  
	hIrDADialog = CreateDialog(MainApp::hInstance,MAKEINTRESOURCE(DLG_IrDA),
		                        DispGetWinHandle(),(DLGPROC)IrDADialogProc);
	
	if (hIrDADialog == NULL)
	{
		print_d("ERROR in creating 'IrDA Command Dialog!");
		MessageBox( DispGetWinHandle(), 
			         "Error: Could not create IrDA Dialog Window",
			         "PC-Simulator: IrDA Command Dialog",
			         (MB_OK | MB_ICONEXCLAMATION) | MB_TASKMODAL );
		return;
	}
	
	ShowWindow(hIrDADialog,SW_SHOW);
}




/////////////////////////////////////////////////////////////////////
void SendIrDAFrame(unsigned char *pSend, unsigned int Length)
/////////////////////////////////////////////////////////////////////
{
	DWORD dwBytesWritten=0, dwError, dwErrorFlags;
	BOOL bWriteState;
	COMSTAT ComStat;
   DWORD dwLastError;

	if (!(hCom==INVALID_HANDLE_VALUE))
	{
		bWriteState=WriteFile(hCom, pSend, (DWORD)Length, &dwBytesWritten, &stOverlapedWrite);
		if (!bWriteState)
		{
         dwLastError = GetLastError();
			if (ERROR_IO_PENDING == dwLastError)
			{
            DWORD dwRes;

            dwRes = WaitForSingleObject(stOverlapedWrite.hEvent, INFINITE);
            switch (dwRes)
            {
               case WAIT_OBJECT_0:
               {
						if (!GetOverlappedResult(hCom, &stOverlapedWrite, &dwBytesWritten, FALSE ))
						{
							dwError = GetLastError();
                     DisplayLastError(DispGetWinHandle(), dwError);
      				}
                  else
                  {
                     // Successful write....??
           				if( dwBytesWritten != Length )
                     {
         					// wenn die Anzahl der zu sendeten Bytes ungleich den gesendeten
                        MessageBox (DispGetWinHandle(),"IRDA: Error by writing to serial port ", NULL, MB_ICONERROR);
                     }
                  }
                  break;
               }

               default:
               {
					   ClearCommError(hCom, &dwErrorFlags, &ComStat) ;
                  MessageBox (DispGetWinHandle(),"IRDA: Error by writing to serial port ", NULL, MB_ICONERROR);
                  break;
               }
            }
			}
			else
			{
				// some other error occurred
				ClearCommError( hCom, &dwErrorFlags, &ComStat );
            DisplayLastError(DispGetWinHandle(), dwLastError);
			} // end of: if(GetLastError()==ERROR_IO_PENDING)
		}
	}
}

/////////////////////////////////////////////////////////////////////
void SetSpeed(unsigned long speed)
/////////////////////////////////////////////////////////////////////
{
	int i;
	DCB dcbCom;
	Sleep(200);

	bIsChanging=TRUE;

   // ----------  Set the UART speed  ----------
	// Load Settings of hCom into Structure dcbCom
	GetCommState(hCom, &dcbCom);	

	// Now figure out how many times to count down from 115200
	switch (speed)
	{
		case 2400: dcbCom.BaudRate=CBR_2400; i=6; break;
		case 4800: dcbCom.BaudRate=CBR_4800; i=5; break;
		case 9600: dcbCom.BaudRate=CBR_9600; i=4; break;
		case 19200: dcbCom.BaudRate=CBR_19200; i=3; break;
		case 38400: dcbCom.BaudRate=CBR_38400; i=2; break;
		case 57600: dcbCom.BaudRate=CBR_57600; i=1; break;
		case 115200: dcbCom.BaudRate=CBR_115200; i=0; break;
	}

	dcbCom.fBinary = TRUE;
	dcbCom.fParity = TRUE;
	dcbCom.fOutxCtsFlow    = FALSE;  // ignore possible hangups
	dcbCom.fOutxDsrFlow    = FALSE;    // don't wait on the DSR line
	dcbCom.fDtrControl     = DTR_CONTROL_DISABLE; //0;
	dcbCom.fDsrSensitivity = FALSE;
	dcbCom.fTXContinueOnXoff = TRUE;
	dcbCom.fOutX           = FALSE; // no XON/XOFF control
	dcbCom.fInX            = FALSE;
	dcbCom.fErrorChar      = FALSE;
	dcbCom.fNull           = FALSE;
	dcbCom.fRtsControl     = RTS_CONTROL_DISABLE; //0
	dcbCom.fAbortOnError   = FALSE;
	dcbCom.ByteSize        = 8;
	dcbCom.Parity          = NOPARITY;
	dcbCom.StopBits        = ONESTOPBIT;

	// Set new Settings to hCom
	SetCommState(hCom, &dcbCom);

	if(dDongle==PAR)
	{	// Parallax Dongle

		// First set the speed to 115200
		EscapeCommFunction(hCom,CLRRTS);

		Sleep(1);

		EscapeCommFunction(hCom,SETRTS);

		// Count down to the appropriate speed
		for (;i > 0; i--)
		{
			EscapeCommFunction(hCom,CLRDTR);

			Sleep(1);

			EscapeCommFunction(hCom,SETDTR);

			Sleep(1);
		}
	}
	else
	{	// Extended Systems Dongle
		switch(speed)
		{
		case 9600:
			EscapeCommFunction(hCom,SETRTS);
			EscapeCommFunction(hCom,CLRDTR);
			break;

		case 19200:
			EscapeCommFunction(hCom,SETDTR);
			EscapeCommFunction(hCom,CLRRTS);
			break;

		case 115200:
			
			EscapeCommFunction(hCom,SETDTR);
			EscapeCommFunction(hCom,SETRTS);
			break;
		
		default:
			break;
		}
	}
	
	
	bIsChanging=FALSE;
}

/////////////////////////////////////////////////////////////////////
void WriteIrDATrace(char * cFile, unsigned char *Msg, unsigned int len, unsigned int uiTyp)
/////////////////////////////////////////////////////////////////////
{
	/*static */char cFileName[MAX_PATH];
	/*static */FILE *fp=NULLP;
	unsigned int i;
	static unsigned int uicount=0;

	if(bTraceIrDA==FALSE)
		return;

	if (uiTyp==0)
	// New Trace File
	{
		// Create file path
		strcpy(cpath,cFile);

		// Does file already exist?
		if((fp=fopen(cpath,"r"))!=NULL)
		{
			fclose(fp);
			if(MessageBox(DispGetWinHandle(),"File already existing! Would you like to replace it?", "Error", MB_ICONERROR|MB_YESNO)==IDYES)
			{
				fp=fopen(cpath,"w");
				fclose(fp);
				ShowMsg(TRUE, REPLACED_FILE);
			}
			else
			{
				ShowMsg(FALSE, DONT_REPLACE_FILE);
				bTraceIrDA=FALSE;
				CheckDlgButton(hwndGlob, IDC_IrDA_CHTR, BST_UNCHECKED);
			}
		}
		else
			ShowMsg(TRUE, CREATED_FILE);
		return;
	}

	
	// Old Trace File
	if (cFileName==NULLP)
		return;
	
	// open File
	fp=fopen(cpath,"a");
	if (fp==NULL)
	{
		MessageBox(DispGetWinHandle(),"Can not access file!", "Error", MB_ICONERROR);
		return;
	}

	// Writing to File
	uicount++;
	if((uiTyp==1)||(uiTyp==2))
	{
		if(uiTyp==1)
			fprintf(fp,"%d Sent %d\n\t",uicount, len);
		else
			fprintf(fp,"%d Recieved %d\n\tC0  ",uicount, len+2);

		for(i=0;i<len;i++)
		{
			fprintf(fp,"%0 2X  ",(BYTE)Msg[i]);
		}
	
		if(uiTyp==1)
			fprintf(fp,"\n");
		else
			fprintf(fp,"C1\n");
	}
	if(uiTyp==3)
	{
		fprintf(fp,"0 %d %s\n",uicount,sWindowMsg);
		sprintf(sWindowMsg,"");
	}

	fclose(fp);
}



BOOL InitialiseIrDAPCMMI(void)
{
	BOOL bHelp;

   ReadIrPCMMIRegistrySetting();

   // -----  Init Com -----
   if(hCom!=INVALID_HANDLE_VALUE)
   {	
      if (IDNO == MessageBox( DispGetWinHandle(), "Com Port already initialised! Do you want to go on?",
                              "PC-Simulator: IrDA Command Dialog",
                              (MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION) | MB_TASKMODAL ))
      {
         return TRUE;
      }
   }

   // -----  Close COM first -----
   CloseCom();
   bHelp=InitCom(uiComNr+1, uiBaudNr); //, hwndDlg);
   // -----  Show message -----
   ShowMsg(bHelp, ACTIVATE);

   // -----  return -----
   if (bHelp==FAILED) 
   {
      return FALSE;
   }
   bIrDAisAct=TRUE;

   return bIrDAisAct;
}


void DeactivateIrDAPCMMI(void)
{
   bIrDAisAct=FALSE;
   ShowMsg(CloseCom(),DEACTIVATE);
}

