/************************************************************************\
 * File Version Information
 * $Header: /Altair32v2/ser_io.c 21    11/08/06 9:21p Racini $
 ************************************************************************/
/************************************************************************\
  MITS Altair Emulator
  Serial Port I/O interface
 
  Copyright (c) 2004 Joseph J. Forgione
  Copyright (c) 2004-2006 Richard A. Cini


Change Log:
  2003/02/18  JJF -- Began coding
  2003/02/22  JJF -- Changed instatus to use flag rather that calling API 
						over and over.
  2003/04/26  RAC -- RELEASE MARKER -- v2.50.2045
  2004/03/09  RAC -- Diff'ed changes from FJS (Fred J. Scipione)
  2004/07/30  RAC -- RELEASE MARKER -- v3.00.0135
  2006/05/12  RAC -- RELEASE MARKER -- v3.10.0200
  2006/11/15  RAC -- RELEASE MARKER -- v3.20.0400
\************************************************************************/
#include <windows.h>	// required for all Windows applications
#include <stdio.h>		// C-lib - I/O
#include <commctrl.h>
#include "altair32.h"	// globals n such
#include "comcthlp.h"	// common control macro file


/**  Forward Prototypes  **************************************/
static BOOL IOpeek(void);
static BOOL SerInit(void);
static int /* FJS */ last_key=0;
static BOOL  siostate=0;


/**************************************************************\
****  Exported Functions  *************************************|
\**************************************************************/
/**************************************************************\
*
*  FUNCTION:    SERIAL_SerInStatus
*
*  INPUTS:      None
*
*  RETURNS:     0 if no data is ready, 1 if data is available
*
*  COMMENTS:		
*
\**************************************************************/
int SERIAL_SerInStatus(void)
{
//	if (GetCommState(hComm,&config_) == 0)
	if (!siostate){
		SerInit();
		return (0);
	}
	else
		return (IOpeek());
}


/**************************************************************\
*
*  FUNCTION:    SERIAL_SerRead
*
*  INPUTS:      None
*
*  RETURNS:     Character (>= 0) or 0 if no data has been read
*
*  COMMENTS:	In order to simulate the way most serial ports
*				work on the Altair, if no data is ready, this
*				routine will return the last character in the
*				buffer, or zero if no characters have ever been
*				put in the buffer.
*
\**************************************************************/
int SERIAL_SerRead(void)
{
	return (last_key);
}


/**************************************************************\
*
*  FUNCTION:    SERIAL_SerOutStatus
*
*  INPUTS:      None
*
*  RETURNS:     1 if data can be written (i.e., buffer isn't full), else 0
*
*  COMMENTS:	Stub TODO: REALLY check the com port
*
\**************************************************************/
int SERIAL_SerOutStatus(void)
{
	return (1);
}


/**************************************************************\
*
*  FUNCTION:    SERIAL_SerWrite
*
*  INPUTS:      Character to write
*
*  RETURNS:     Nothing
*
*  COMMENTS:	No error reporting. What could go wrong?;)
*
\**************************************************************/
void SERIAL_SerWrite(UCHAR cData)
{
	DWORD NumBytesWritten;
	WriteFile(hComm, &cData, 1, &NumBytesWritten, 0);
}


/**************************************************************\
*
*  FUNCTION:    SERIAL_SerShutdown - Close com port
*
*  INPUTS:      None
*
*  RETURNS:     Nothing
*
*  COMMENTS:	
\**************************************************************/

BOOL SERIAL_SerShutdown(void)
{
	//DWORD NumBytesWritten;	

	//WriteFile(hComm,"\n\rBye!\n\r",22,&NumBytesWritten,NULL);
	CloseHandle(hComm);
	siostate = FALSE;
	return TRUE;
}
	

/**************************************************************\
****  Internal Subroutines  ***********************************|
\**************************************************************/
/**************************************************************\
*
*  FUNCTION:    SerInit
*
*  INPUTS:      None
*
*  RETURNS:     TRUE if Requested port was opened
*
*  COMMENTS:	
*
\**************************************************************/
static BOOL SerInit(void)
{
	char buf[128];
	COMMTIMEOUTS timeouts;
	comport = S_port;
	hComm = CreateFile(comport,		// 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. 
 //   FILE_FLAG_OVERLAPPED,             // default.
 0, 
 NULL);									// default.

	if (GetCommState(hComm,&config_) == 0){
		sprintf(buf, "Error opening COM port %s",comport );
		MessageBox(winstate.hWnd, buf, "Confirm",
			    MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TOPMOST);
		return FALSE;
		}
		
	SetupComm(hComm, 32, 32);
		
	// We got a port! now lets config it the way we want
	config_.BaudRate = baudrate;          // Current baud 
	config_.fBinary = TRUE;               // Binary mode; no EOF check 
	config_.fParity = TRUE;               // Enable parity checking 
	config_.fOutxCtsFlow = FALSE;         // No CTS output flow control 
	config_.fOutxDsrFlow = FALSE;         // No DSR output flow control 
	config_.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type 
	config_.fDsrSensitivity = TRUE;      // DSR sensitivity 
	config_.fTXContinueOnXoff = FALSE;     // XOFF continues Tx 
	config_.fOutX = FALSE;                // No XON/XOFF out flow control 
	config_.fInX = FALSE;                 // No XON/XOFF in flow control 
	config_.fErrorChar = FALSE;           // Disable error replacement 
	config_.fNull = FALSE;                // Disable null stripping 
	config_.fRtsControl = RTS_CONTROL_DISABLE; //Disable RTS flow control
	config_.fAbortOnError = FALSE;        // Do not abort reads/writes on error
	config_.ByteSize = 8;                 // Number of bits/byte, 4-8 
	config_.Parity = NOPARITY;            // 0-4=no,odd,even,mark,space 
	config_.StopBits = ONESTOPBIT;        // 0,1,2 = 1, 1.5, 2 
  
  	if (!SetCommState (hComm, &config_)){
		sprintf(buf, "Error opening COM port %s",comport );
		MessageBox(winstate.hWnd, buf, "Confirm",
			    MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TOPMOST);
		return FALSE;
		}
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts( hComm, &timeouts );
	siostate=TRUE;

	sprintf(buf,"%s:%i",comport,config_.BaudRate);
	Status_SetText(hwndStatusBar, STATBAR_CONS, 0, buf);	
//	sprintf(buf,"\n\rAltair EMU Online\n\r");
//	WriteFile (hComm,buf,22,&NumBytesWritten,NULL);
	return TRUE;
}


static BOOL IOpeek(void)
{
	DWORD Bytesxfer;
	CHAR cdata;	

	ReadFile(hComm, &cdata, 1, &Bytesxfer, 0);
	if (Bytesxfer != 0){
		last_key=cdata;
		return TRUE;
	}
	else
		return FALSE;
}
/* end of file: ser_io.c */
