前一阵,从国外网站看到一个用C#来操作串口的类。下载下来试了一下,觉得不错。共享一下。
/*
- Author: Marcus Lorentzon, 2001
- [email protected]
- Freeware: Please do not remove this header
- File: SerialStream.cs
- Description: Implements a Stream for asynchronous
- transfers and COMM. Stream version.
- Version: 2.4
*/
#region Using
using System;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.ComponentModel;
#endregion Using
namespace LoMaN.IO {
public class SerialStream : Stream {
#region Attributes
private IOCompletionCallback m_IOCompletionCallback;
private IntPtr m_hFile = IntPtr.Zero;
private string m_sPort;
private bool m_bRead;
private bool m_bWrite;
#endregion Attributes
#region Properties
public string Port {
get {
return m_sPort;
}
set {
if (m_sPort != value) {
Close();
Open(value);
}
}
}
public override bool CanRead {
get {
return m_bRead;
}
}
public override bool CanWrite {
get {
return m_bWrite;
}
}
public override bool CanSeek {
get {
return false ;
}
}
public bool Closed {
get {
return m_hFile.ToInt32() 0 ;
}
}
public bool Dsr {
get {
uint status;
if ( ! GetCommModemStatus(m_hFile, out status)) {
throw new Win32Exception();
}
return (status & MS_DSR_ON) > 0 ;
}
}
public bool Ring {
get {
uint status;
if ( ! GetCommModemStatus(m_hFile, out status)) {
throw new Win32Exception();
}
return (status & MS_RING_ON) > 0 ;
}
}
public bool Rlsd {
get {
uint status;
if ( ! GetCommModemStatus(m_hFile, out status)) {
throw new Win32Exception();
}
return (status & MS_RLSD_ON) > 0 ;
}
}
#endregion Properties
#region Constructors
public SerialStream() : this (FileAccess.ReadWrite) {
}
public SerialStream(FileAccess access) {
m_bRead = (( int )access & ( int )FileAccess.Read) != 0 ;
m_bWrite = (( int )access & ( int )FileAccess.Write) != 0 ;
unsafe {
m_IOCompletionCallback = new IOCompletionCallback(AsyncFSCallback);
}
}
public SerialStream( string port) : this (FileAccess.ReadWrite) {
Open(port);
}
public SerialStream( string port, FileAccess access) : this (access) {
Open(port);
}
#endregion Constructors
#region Methods
public void Open( string port) {
if (m_hFile != IntPtr.Zero) {
throw new IOException( " Stream already opened. " );
}
m_sPort = port;
m_hFile = CreateFile(port, ( uint )((m_bRead ? GENERIC_READ: 0 ) | (m_bWrite ? GENERIC_WRITE: 0 )), 0 , 0 , OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
if (m_hFile.ToInt32() == INVALID_HANDLE_VALUE) {
m_hFile = IntPtr.Zero;
throw new FileNotFoundException( " Unable to open " + port);
}
ThreadPool.BindHandle(m_hFile);
SetTimeouts( 0 , 0 , 0 , 0 , 0 );
}
public override void Close() {
CloseHandle(m_hFile);
m_hFile = IntPtr.Zero;
m_sPort = null ;
}
public IAsyncResult BeginRead( byte [] buffer) {
return BeginRead(buffer, 0 , buffer.Length, null , null );
}
public override IAsyncResult BeginRead( byte [] buffer, int offset, int count, AsyncCallback callback, object state) {
GCHandle gchBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
SerialAsyncResult sar = new SerialAsyncResult( this , state, callback, true , gchBuffer);
Overlapped ov = new Overlapped( 0 , 0 , sar.AsyncWaitHandle.Handle.ToInt32(), sar);
unsafe {
NativeOverlapped * nov = ov.Pack(m_IOCompletionCallback);
byte * data = ( byte * )(( int )gchBuffer.AddrOfPinnedObject() + offset);
uint read = 0 ;
if (ReadFile(m_hFile, data, ( uint )count, out read, nov)) {
sar.m_bCompletedSynchronously = true ;
return sar;
}
else if (GetLastError() == ERROR_IO_PENDING) {
return sar;
}
else
throw new Exception( " Unable to initialize read. Errorcode: " + GetLastError().ToString());
}
}
public IAsyncResult BeginWrite( byte [] buffer) {
return BeginWrite(buffer, 0 , buffer.Length, null , null );
}
public override IAsyncResult BeginWrite( byte [] buffer, int offset, int count, AsyncCallback callback, object state) {
GCHandle gchBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
SerialAsyncResult sar = new SerialAsyncResult( this , state, callback, false , gchBuffer);
Overlapped ov = new Overlapped( 0 , 0 , sar.AsyncWaitHandle.Handle.ToInt32(), sar);
unsafe {
NativeOverlapped * nov = ov.Pack(m_IOCompletionCallback);
byte * data = ( byte * )(( int )gchBuffer.AddrOfPinnedObject() + offset);
uint written = 0 ;
if (WriteFile(m_hFile, data, ( uint )count, out written, nov)) {
sar.m_bCompletedSynchronously = true ;
return sar;
}
else if (GetLastError() == ERROR_IO_PENDING) {
return sar;
}
else
throw new Exception( " Unable to initialize write. Errorcode: " + GetLastError().ToString());
}
}
private int EndOperation(IAsyncResult asyncResult, bool isRead) {
SerialAsyncResult sar = (SerialAsyncResult)asyncResult;
if (sar.m_bIsRead != isRead)
throw new IOException( " Invalid parameter: IAsyncResult is not from a " + (isRead ? " read " : " write " ));
if (sar.EndOperationCalled) {
throw new IOException( " End " + (isRead ? " Read " : " Write " ) + " called twice for the same operation. " );
}
else {
sar.m_bEndOperationCalled = true ;
}
while ( ! sar.m_bCompleted) {
sar.AsyncWaitHandle.WaitOne();
}
sar.Dispose();
if (sar.m_nErrorCode != ERROR_SUCCESS && sar.m_nErrorCode != ERROR_OPERATION_ABORTED) {
throw new IOException( " Operation finished with errorcode: " + sar.m_nErrorCode);
}
return sar.m_nReadWritten;
}
public override int EndRead(IAsyncResult asyncResult) {
return EndOperation(asyncResult, true );
}
public override void EndWrite(IAsyncResult asyncResult) {
EndOperation(asyncResult, false );
}
public int EndWriteEx(IAsyncResult asyncResult) {
return EndOperation(asyncResult, false );
}
public override int Read( byte [] buffer, int offset, int count) {
return EndRead(BeginRead(buffer, offset, count, null , null ));
}
public override void Write( byte [] buffer, int offset, int count) {
EndWrite(BeginWrite(buffer, offset, count, null , null ));
}
public int WriteEx( byte [] buffer, int offset, int count) {
return EndWriteEx(BeginWrite(buffer, offset, count, null , null ));
}
public int Read( byte [] buffer) {
return EndRead(BeginRead(buffer, 0 , buffer.Length, null , null ));
}
public int Write( byte [] buffer) {
return EndOperation(BeginWrite(buffer, 0 , buffer.Length, null , null ), false );
}
public override void Flush() {
FlushFileBuffers(m_hFile);
}
public bool PurgeRead() {
return PurgeComm(m_hFile, PURGE_RXCLEAR);
}
public bool PurgeWrite() {
return PurgeComm(m_hFile, PURGE_TXCLEAR);
}
public bool Purge() {
return PurgeRead() && PurgeWrite();
}
public bool CancelRead() {
return PurgeComm(m_hFile, PURGE_RXABORT);
}
public bool CancelWrite() {
return PurgeComm(m_hFile, PURGE_TXABORT);
}
public bool CancelAll() {
return CancelRead() && CancelWrite();
}
public override void SetLength( long nLength) {
throw new NotSupportedException( " SetLength isn't supported on serial ports. " );
}
public override long Seek( long offset, SeekOrigin origin) {
throw new NotSupportedException( " Seek isn't supported on serial ports. " );
}
public void SetTimeouts( int ReadIntervalTimeout,
int ReadTotalTimeoutMultiplier,
int ReadTotalTimeoutConstant,
int WriteTotalTimeoutMultiplier,
int WriteTotalTimeoutConstant) {
SerialTimeouts Timeouts = new SerialTimeouts(ReadIntervalTimeout,
ReadTotalTimeoutMultiplier,
ReadTotalTimeoutConstant,
WriteTotalTimeoutMultiplier,
WriteTotalTimeoutConstant);
unsafe { SetCommTimeouts(m_hFile, ref Timeouts); }
}
public bool SetPortSettings( uint baudrate) {
return SetPortSettings(baudrate, FlowControl.Hardware);
}
public bool SetPortSettings( uint baudrate, FlowControl flowControl) {
return SetPortSettings(baudrate, flowControl, Parity.None);
}
public bool SetPortSettings( uint baudrate, FlowControl flowControl, Parity parity) {
return SetPortSettings(baudrate, flowControl, parity, 8 , StopBits.One);
}
public bool SetPortSettings( uint baudrate, FlowControl flowControl, Parity parity, byte databits, StopBits stopbits) {
unsafe {
DCB dcb = new DCB();
dcb.DCBlength = sizeof (DCB);
dcb.BaudRate = baudrate;
dcb.ByteSize = databits;
dcb.StopBits = ( byte )stopbits;
dcb.Parity = ( byte )parity;
dcb.fParity = (parity > 0 ) ? 1U : 0U ;
dcb.fBinary = dcb.fDtrControl = dcb.fTXContinueOnXoff = 1 ;
dcb.fOutxCtsFlow = dcb.fAbortOnError = (flowControl == FlowControl.Hardware) ? 1U : 0U ;
dcb.fOutX = dcb.fInX = (flowControl == FlowControl.XOnXOff) ? 1U : 0U ;
dcb.fRtsControl = (flowControl == FlowControl.Hardware) ? 2U : 1U ;
dcb.XonLim = 2048 ;
dcb.XoffLim = 512 ;
dcb.XonChar = 0x11 ; // Ctrl-Q
dcb.XoffChar = 0x13 ; // Ctrl-S
return SetCommState(m_hFile, ref dcb);
}
}
public bool SetPortSettings(DCB dcb) {
return SetCommState(m_hFile, ref dcb);
}
public bool GetPortSettings( out DCB dcb) {
unsafe {
DCB dcb2 = new DCB();
dcb2.DCBlength = sizeof (DCB);
bool ret = GetCommState(m_hFile, ref dcb2);
dcb = dcb2;
return ret;
}
}
public bool SetXOn() {
return EscapeCommFun