//xiaotao shu
//serial port communication program
//2004. spet.

using System.IO;
using System;
using System.Runtime.InteropServices;

//namespace  SerialPort
namespace client
{
	public class SerialPort
	{
		public SerialPort()
		{
			PortNum = "COM1:";   // 1	       prot number
			BaudRate = 1200;     // 1200       baud rate
			ByteSize = 8;        // 8bits      data bit
			Parity = 0;          // 0-4=no,odd,even,mark,space   verfiy bit
			StopBits = 1;        // 0,1,2 = 1, 1.5, 2            stop bit
		}

		#region constants from API
		//win32 api constants 
		private const uint GENERIC_READ = 0x80000000; 
		private const uint GENERIC_WRITE = 0x40000000; 
		private const int OPEN_EXISTING = 3;       
		private const int INVALID_HANDLE_VALUE = -1; 
		private const int EV_RXCHAR = 1;                 //  Any Character received


       
		[StructLayout(LayoutKind.Sequential)] 
			private struct DCB  
		{ 
			//taken from c struct in platform sdk  
			public int DCBlength;           // sizeof(DCB)  
			public int BaudRate;            // current baud rate  
			public int fBinary;          // binary mode, no EOF check  
			public int fParity;          // enable parity checking  
			public int fOutxCtsFlow;      // CTS output flow control  
			public int fOutxDsrFlow;      // DSR output flow control  
			public int fDtrControl;       // DTR flow control type  
			public int fDsrSensitivity;   // DSR sensitivity  
			public int fTXContinueOnXoff; // XOFF continues Tx  
			public int fOutX;          // XON/XOFF out flow control  
			public int fInX;           // XON/XOFF in flow control  
			public int fErrorChar;     // enable error replacement  
			public int fNull;          // enable null stripping  
			public int fRtsControl;     // RTS flow control  
			public int fAbortOnError;   // abort on error  
			public int fDummy2;        // reserved  
			public ushort wReserved;          // not currently used  
			public ushort XonLim;             // transmit XON threshold  
			public ushort XoffLim;            // transmit XOFF threshold  
			public byte ByteSize;           // number of bits/byte, 4-8  
			public byte Parity;             // 0-4=no,odd,even,mark,space  
			public byte StopBits;           // 0,1,2 = 1, 1.5, 2  
			public char XonChar;            // Tx and Rx XON character  
			public char XoffChar;           // Tx and Rx XOFF character  
			public char ErrorChar;          // error replacement character  
			public char EofChar;            // end of input character  
			public char EvtChar;            // received event character  
			public ushort wReserved1;         // reserved; do not use  
		} 

		[StructLayout(LayoutKind.Sequential)] 
			private struct COMMTIMEOUTS  
		{   
			public int ReadIntervalTimeout;  
			public int ReadTotalTimeoutMultiplier;  
			public int ReadTotalTimeoutConstant;  
			public int WriteTotalTimeoutMultiplier;  
			public int WriteTotalTimeoutConstant;  
		}     

		[StructLayout(LayoutKind.Sequential)]    
			private struct OVERLAPPED  
		{  
			public int  Internal;  
			public int  InternalHigh;  
			public int  Offset;  
			public int  OffsetHigh;  
			public int hEvent;  
		}   
       
		[DllImport("kernel32")] 
		private static extern int CreateFile( 
			string lpFileName,                      // file name 
			uint dwDesiredAccess,                   // access mode 
			int dwShareMode,                        // share mode 
			int lpSecurityAttributes,               // SD 
			int dwCreationDisposition,              // how to create 
			int dwFlagsAndAttributes,               // file attributes 
			int hTemplateFile                       // handle to template file 
			); 
		[DllImport("kernel32")] 
		private static extern bool GetCommState( 
			int hFile,       // handle to communications device 
			ref DCB lpDCB    // device-control block 
			);    
		[DllImport("kernel32")] 
		private static extern bool BuildCommDCB( 
			string lpDef,     // device-control string 
			ref DCB lpDCB     // device-control block 
			); 
		[DllImport("kernel32")] 
		private static extern bool SetCommState( 
			int hFile,       // handle to communications device 
			ref DCB lpDCB    // device-control block 
			); 
		[DllImport("kernel32")] 
		private static extern bool GetCommTimeouts( 
			int hFile,                       // handle to comm device 
			ref COMMTIMEOUTS lpCommTimeouts  // time-out values 
			);    
		[DllImport("kernel32")]    
		private static extern bool SetCommTimeouts( 
			int hFile,                       // handle to comm device 
			ref COMMTIMEOUTS lpCommTimeouts  // time-out values 
			); 
		[DllImport( "kernel32")] 
		private static extern bool ReadFile( 
			int hFile,                   // handle to file 
			byte[] lpBuffer,             // data buffer 
			int nNumberOfBytesToRead,    // number of bytes to read 
			ref int lpNumberOfBytesRead, // number of bytes read 
			ref OVERLAPPED lpOverlapped  // overlapped buffer 
			); 
		[DllImport("kernel32")] 
		private static extern bool WriteFile( 
			int hFile,                       // handle to file 
			byte[] lpBuffer,                 // data buffer 
			int nNumberOfBytesToWrite,       // number of bytes to write 
			ref int lpNumberOfBytesWritten,  // number of bytes written 
			ref OVERLAPPED lpOverlapped      // overlapped buffer 
			); 
		[DllImport("kernel32")] 
		private static extern bool CloseHandle( 
			int hObject   // handle to object 
			); 

		[DllImport("kernel32.dll")]
		private static extern int SetCommMask (
			int hFile, 
			int dwEvtMask
			); 

		[DllImport("kernel32.dll")]
		private static extern int WaitCommEvent (
			int hFile,
			ref int lpEvtMask, 
			ref OVERLAPPED lpOverlapped
			);  

	   #endregion 
		#region attributes
		public  string PortNum;   // 1	              
		public  int BaudRate;     // 1200      
		public  byte ByteSize;    // 8bits                      
		public  byte Parity;      // 0-4=no,odd,even,mark,space   
		public  byte StopBits;    // 0,1,2 = 1, 1.5, 2            
		public  int ReadTimeout;  //                              read timeout
		public  int InitOK;

		//comm port win32 file handle 
		public  int hComm = -1; 
		public  bool hCommRead = false; 
		public  bool Opened = false; 

		//read write buffers
		public  byte[] InByteData;     //send data
		public  byte[] OutByteData;    //read data
		#endregion 

		/// <summary>
		///com port initialize 
		///lpFileName		port name
		///baudRate			baud rate
		///parity			verfiy bit
		/// <summary>
		public  bool PortInitialize(string aPortNum,int aBaudrate,byte aByteSize,byte aParity, byte StopBits)  
		{ 
			try
			{
				PortNum = aPortNum;  
				BaudRate = aBaudrate;    
				ByteSize = aByteSize;       
				Parity = aParity;         
				StopBits = StopBits;  
				InitOK = 1;
				//open the port
				DCB dcbCommPort = new DCB(); 
				COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();    
        
        
				// open the comm port 
				hComm = CreateFile(PortNum ,GENERIC_READ | GENERIC_WRITE,0, 0,OPEN_EXISTING,0,0); 
       
				// if port cannot be opened, bail out
				if(hComm == INVALID_HANDLE_VALUE)  
				{ 
					throw(new ApplicationException("Open the serial port failed!")); 
					//return false;
				} 
       
				// Set the comm timeout
          		GetCommTimeouts(hComm,ref ctoCommPort); 
				ctoCommPort.ReadIntervalTimeout = 0;//Int32.MaxValue;
				ctoCommPort.ReadTotalTimeoutConstant = 500;//0; 
				ctoCommPort.ReadTotalTimeoutMultiplier = 0; 
				ctoCommPort.WriteTotalTimeoutMultiplier = 0;//10; 
				ctoCommPort.WriteTotalTimeoutConstant = 500;//1000;   
				SetCommTimeouts(hComm,ref ctoCommPort); 
       
				// SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS. 
				dcbCommPort.DCBlength = Marshal.SizeOf(dcbCommPort); 
				GetCommState(hComm, ref dcbCommPort); 
				dcbCommPort.BaudRate=BaudRate; 
				dcbCommPort.Parity=Parity; 
				dcbCommPort.ByteSize=ByteSize; 
				dcbCommPort.StopBits=StopBits; 
				SetCommState(hComm, ref dcbCommPort); 
         
				Opened = true; 
				return true;
			}
			catch
			{
				InitOK = 0; 			  
				return false;
			}
		} 

		public void Close()  
		{ 
			if (hComm!=INVALID_HANDLE_VALUE)  
			{ 
				CloseHandle(hComm); 
			} 
		}
		public void Write(byte[] WriteBytes)  
		{ 
			if (hComm!=INVALID_HANDLE_VALUE)  
			{ 
				OVERLAPPED ovlCommPort = new OVERLAPPED(); 
				int BytesWritten = 0; 
				WriteFile(hComm,WriteBytes,WriteBytes.Length,ref BytesWritten,ref ovlCommPort); 
			} 
			else  
			{ 
				throw(new ApplicationException("open the serial port fialed!")); 
			}       
		}
		public byte[]  Read(int NumBytes)  
		{ 
			byte[] BufBytes; 
			byte[] OutBytes; 
			BufBytes = new byte[NumBytes]; 
			if (hComm!=INVALID_HANDLE_VALUE)  
			{ 
				OVERLAPPED ovlCommPort = new OVERLAPPED(); 
				int BytesRead=0; 
				hCommRead=ReadFile(hComm,BufBytes,NumBytes,ref BytesRead,ref ovlCommPort); 
				OutBytes = new byte[BytesRead]; 
				Array.Copy(BufBytes,OutBytes,BytesRead); 
			}  
			else  
			{ 
				throw(new ApplicationException("open the serial port fialed!!")); 
			} 
            return OutBytes; 
		} 

		//serial port monitor continues listening the com port
		//it run at m_thread. when m_thread is aborted, it terminate   
		public void monitorSerialPort(ClientForm aParent)
		{
			int dwCommEvent =0;
			OVERLAPPED ovlCommPort = new OVERLAPPED(); 
			
			SetCommMask(hComm, EV_RXCHAR);
			while ( true )
			{
				SetCommMask(hComm, EV_RXCHAR);
				if (WaitCommEvent(hComm, ref dwCommEvent, ref ovlCommPort)==1) 
				{
					StreamWriter fs = File.AppendText("log.dat");
					char[] buffer;
					byte[] readBytes;
					String aMessage=null;
					readBytes =Read(512);
					buffer = new char[readBytes.Length];
					Array.Copy(readBytes,buffer,readBytes.Length); 
					aMessage = new String(buffer);
					if (aMessage.Trim().Length>0)
						fs.Write(buffer);
					fs.Close();
					if (aMessage.Trim().Length > 17) //position 17 chars, 
					{
						//call the client's main thread(GUI thread) receiveFromComPort 
						//send message receiving from com port to main thread
						aParent.receiveFromComPort(aMessage);
					}
					if (aParent.m_stop)
						break;
					SetCommMask(hComm, EV_RXCHAR);
				}
			}
		}

	} //end serialPort class
} //end namespace
