Serial通信的例子(一)

发表于:2007-06-30来源:作者:点击数: 标签:
namespace LoMaN.IO { using System; using System.IO; using System.Threading; using System.Runtime.InteropServices; public class SerialStream : Stream { public class SerialAsyncResult : IAsyncResult { public SerialAsyncResult(object asyncObje
namespace LoMaN.IO {

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

    public class SerialStream : Stream {

        public class SerialAsyncResult : IAsyncResult {
            public SerialAsyncResult(object asyncObject) {
                m_AsyncObject = asyncObject;
                m_WaitHandle = new ManualResetEvent(false);
            }

            internal void Init(object stateObject, AsyncCallback callback, bool bIsRead) {
                m_StateObject = stateObject;
                m_Callback = callback;
                m_bIsRead = bIsRead;
                m_bCompleted = false;
                m_WaitHandle.Reset();
            }

            internal void Reset() {
                m_StateObject = null;
                m_Callback = null;
                m_bCompleted = true;
                m_WaitHandle.Reset();
            }

            internal bool m_bIsRead;
            internal bool m_bCompleted = true;

            public bool IsCompleted { get { return m_bCompleted; } }
            public bool CompletedSynchronously { get { return false; } }

            private object m_AsyncObject;
            public object AsyncObject { get { return m_AsyncObject; } }

            private object m_StateObject;
            public object AsyncState { get { return m_StateObject; } }

            private ManualResetEvent m_WaitHandle;
            public WaitHandle AsyncWaitHandle { get { return m_WaitHandle; } }

            private AsyncCallback m_Callback;
            public AsyncCallback Callback { get { return m_Callback; } }
        }
        
        private unsafe void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped) {
            SerialAsyncResult sar = (SerialAsyncResult)Overlapped.Unpack(pOverlapped).AsyncResult;

            if (sar.m_bIsRead)
                m_iReadCount = (int)numBytes;
            else
                m_iWriteCount = (int)numBytes;
            ((ManualResetEvent)sar.AsyncWaitHandle).Set();

            if (errorCode == ERROR_OPERATION_ABORTED)
                sar.m_bCompleted = false;
            else
                sar.m_bCompleted = true;

            if (sar.Callback != null)
                sar.Callback.Invoke(sar);
        }

        private IOCompletionCallback m_IOCompletionCallback;
        private int m_hFile = 0;

        private string m_sPort;
        public string Port {
            get {
                return m_sPort;
            }
            set {
                if (m_sPort != value) {
                    Close();
                    Open(value);
                }
            }
        }

        private const uint GENERIC_READ = 0x80000000;
        private const uint GENERIC_WRITE = 0x40000000;
        private const uint ERROR_OPERATION_ABORTED = 995;
        private const uint ERROR_IO_PENDING = 997;

        public void Open(string port) {
            m_hFile = CreateFile(port, (uint)((m_bRead?GENERIC_READ:0)|(m_bWrite?GENERIC_WRITE:0)), 0, 0, 3, 0x40000000, 0);
            if (m_hFile <= 0) {
                m_hFile = 0;
                throw new FileNotFoundException("Unable to open " + port);
            }
            m_sPort = port;

            ThreadPool.BindHandle(new IntPtr(m_hFile));
        }

        public SerialStream(string port, FileAclearcase/" target="_blank" >ccess access) {
            m_bRead  = ((int)access & (int)FileAccess.Read) != 0;
            m_bWrite = ((int)access & (int)FileAccess.Write) != 0;
            Open(port);
            unsafe {
                m_IOCompletionCallback = new IOCompletionCallback(AsyncFSCallback);
            }
        }

        private bool m_bRead;
        public override bool CanRead { get { return m_bRead; } }

        private bool m_bWrite;
        public override bool CanWrite { get { return m_bWrite; } }

        public override bool CanSeek { get { return false; } }

        public bool Closed  { get { return m_hFile <= 0; } }

        public override long Length { get { return 0; } }

        public override void SetLength(long nLength) { }

        public override void Close() {
            CloseHandle(m_hFile);
            m_hFile = 0;
            m_sPort = null;
        }

        private int m_iReadCount;
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
            SerialAsyncResult ar = new SerialAsyncResult(this);
            ar.Init(state, callback, true);
            Overlapped ov = new Overlapped(0, 0, ar.AsyncWaitHandle.Handle.ToInt32(), ar);
            unsafe { fixed (byte* data = &buffer[0]) {
                int read = 0;
                NativeOverlapped* nov = ov.Pack(m_IOCompletionCallback);
                ReadFile(m_hFile, data, count, &read, nov);
            } }

            if (GetLastError() == ERROR_IO_PENDING)
                return ar;
            else
                throw new Exception("Unable to initialize read. Errorcode: " + GetLastError().ToString());
        }

        private int m_iWriteCount;
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
            SerialAsyncResult ar = new SerialAsyncResult(this);
            ar.Init(state, callback, false);
            Overlapped ov = new Overlapped(0, 0, ar.AsyncWaitHandle.Handle.ToInt32(), ar);
            unsafe { fixed (byte* data = &buffer[0]) {
                int write = 0;
                NativeOverlapped* nov = ov.Pack(m_IOCompletionCallback);
                WriteFile(m_hFile, data, count, &write, nov);
            } }
            if (GetLastError() == ERROR_IO_PENDING)
                return ar;
            else
                throw new Exception("Unable to initialize write. Errorcode: " + GetLastError().ToString());
        }
        
        public override int EndRead(IAsyncResult asyncResult) {
            SerialAsyncResult sar = (SerialAsyncResult)asyncResult;
            if (!sar.m_bIsRead)
                throw new Exception("Invalid parameter: IAsyncResult is not from a read");
            sar.AsyncWaitHandle.WaitOne();
            if (!sar.m_bCompleted) {
                ((ManualResetEvent)sar.AsyncWaitHandle).Reset();
                sar.AsyncWaitHandle.WaitOne();
            }
            sar.Reset();

            return m_iReadCount;
        }
        
        public override void EndWrite(IAsyncResult asyncResult) {
            SerialAsyncResult sar = (SerialAsyncResult)asyncResult;
            if (sar.m_bIsRead)
                throw new Exception("Invalid parameter: IAsyncResult is from a read");
            sar.AsyncWaitHandle.WaitOne();
            if (!sar.m_bCompleted) {
                ((ManualResetEvent)sar.AsyncWaitHandle).Reset();
                sar.AsyncWaitHandle.WaitOne();
            }
            sar.Reset();
        }

        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 override void Flush() { FlushFileBuffers(m_hFile); }

        private const uint PURGE_TXABORT = 0x0001;  // Kill the pending/current writes to the comm port.
        private const uint PURGE_RXABORT = 0x0002;  // Kill the pending/current reads to the comm port.
        private const uint PURGE_TXCLEAR = 0x0004;  // Kill the transmit queue if there.
        private const uint PURGE_RXCLEAR = 0x0008;  // Kill the typeahead buffer if there.

        public bool PurgeRead() { return(PurgeComm(m_hFile, PURGE_RXCLEAR)); }
        public bool PurgeWrite() { return(PurgeComm(m_hFile, PURGE_TXCLEAR)); }
        public bool CancelRead() { return(PurgeComm(m_hFile, PURGE_RXABORT)); }
        public bool CancelWrite() { return(PurgeComm(m_hFile, PURGE_TXABORT)); }

        public override long Seek(long offset, SeekOrigin origin) { return 0; }

        

原文转自:http://www.ltesting.net