zoukankan      html  css  js  c++  java
  • C#串口操作

    #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 EscapeCommFunction(m_hFile, SETXON);
            }

            public bool SetXOff() {
                return EscapeCommFunction(m_hFile, SETXOFF);
            }

            private unsafe void AsyncFSCallback(uint errorCode, uint numBytes, NativeOverlapped* pOverlapped) {
                SerialAsyncResult sar = (SerialAsyncResult)Overlapped.Unpack(pOverlapped).AsyncResult;

                sar.m_nErrorCode = errorCode;
                sar.m_nReadWritten = (int)numBytes;
                sar.m_bCompleted = true;

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

                Overlapped.Free(pOverlapped);
            }

            #endregion Methods

            #region Constants

            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.

            private const uint SETXOFF  = 1;    // Simulate XOFF received
            private const uint SETXON   = 2;    // Simulate XON received
            private const uint SETRTS    = 3;    // Set RTS high
            private const uint CLRRTS    = 4;    // Set RTS low
            private const uint SETDTR    = 5;    // Set DTR high
            private const uint CLRDTR    = 6;    // Set DTR low
            private const uint SETBREAK    = 8;    // Set the device break line.
            private const uint CLRBREAK    = 9;    // Clear the device break line.

            private const uint MS_CTS_ON  = 0x0010;
            private const uint MS_DSR_ON  = 0x0020;
            private const uint MS_RING_ON = 0x0040;
            private const uint MS_RLSD_ON = 0x0080;

            private const uint FILE_FLAG_OVERLAPPED = 0x40000000;

            private const uint OPEN_EXISTING = 3;

            private const int  INVALID_HANDLE_VALUE = -1;

            private const uint GENERIC_READ = 0x80000000;
            private const uint GENERIC_WRITE = 0x40000000;

            private const uint ERROR_SUCCESS = 0;
            private const uint ERROR_OPERATION_ABORTED = 995;
            private const uint ERROR_IO_PENDING = 997;

            #endregion Constants

            #region Enums

            public enum Parity {None, Odd, Even, Mark, Space};
            public enum StopBits {One, OneAndHalf, Two};
            public enum FlowControl {None, XOnXOff, Hardware};

            #endregion Enums

            #region Classes

            [StructLayout(LayoutKind.Sequential)]
            public struct DCB {

                #region Attributes

                public int DCBlength;
                public uint BaudRate;
                public uint Flags;
                public ushort wReserved;
                public ushort XonLim;
                public ushort XoffLim;
                public byte ByteSize;
                public byte Parity;
                public byte StopBits;
                public sbyte XonChar;
                public sbyte XoffChar;
                public sbyte ErrorChar;
                public sbyte EofChar;
                public sbyte EvtChar;
                public ushort wReserved1;

                #endregion Attributes

                #region Properties

                public uint fBinary { get { return Flags&0x0001; }
                                      set { Flags = Flags & ~1U | value; } }
                public uint fParity { get { return (Flags>>1)&1; }
                                      set { Flags = Flags & ~(1U >2)&1; }
                                      set { Flags = Flags & ~(1U >3)&1; }
                                      set { Flags = Flags & ~(1U >4)&3; }
                                      set { Flags = Flags & ~(3U >6)&1; }
                                      set { Flags = Flags & ~(1U >7)&1; }
                                      set { Flags = Flags & ~(1U >8)&1; }
                                      set { Flags = Flags & ~(1U >9)&1; }
                                      set { Flags = Flags & ~(1U >10)&1; }
                                      set { Flags = Flags & ~(1U >11)&1; }
                                      set { Flags = Flags & ~(1U >12)&3; }
                                      set { Flags = Flags & ~(3U >14)&1; }
                                      set { Flags = Flags & ~(1U << 14) | (value << 14); } }

                #endregion Properties

                #region Methods

                public override string ToString() {
                    return "DCBlength: " + DCBlength + "\r\n" +
                        "BaudRate: " + BaudRate + "\r\n" +
                        "fBinary: " + fBinary + "\r\n" +
                        "fParity: " + fParity + "\r\n" +
                        "fOutxCtsFlow: " + fOutxCtsFlow + "\r\n" +
                        "fOutxDsrFlow: " + fOutxDsrFlow + "\r\n" +
                        "fDtrControl: " + fDtrControl + "\r\n" +
                        "fDsrSensitivity: " + fDsrSensitivity + "\r\n" +
                        "fTXContinueOnXoff: " + fTXContinueOnXoff + "\r\n" +
                        "fOutX: " + fOutX + "\r\n" +
                        "fInX: " + fInX + "\r\n" +
                        "fErrorChar: " + fErrorChar + "\r\n" +
                        "fNull: " + fNull + "\r\n" +
                        "fRtsControl: " + fRtsControl + "\r\n" +
                        "fAbortOnError: " + fAbortOnError + "\r\n" +
                        "XonLim: " + XonLim + "\r\n" +
                        "XoffLim: " + XoffLim + "\r\n" +
                        "ByteSize: " + ByteSize + "\r\n" +
                        "Parity: " + Parity + "\r\n" +
                        "StopBits: " + StopBits + "\r\n" +
                        "XonChar: " + XonChar + "\r\n" +
                        "XoffChar: " + XoffChar + "\r\n" +
                        "EofChar: " + EofChar + "\r\n" +
                        "EvtChar: " + EvtChar + "\r\n";
                }

                #endregion Methods
            }

            private class SerialAsyncResult : IAsyncResult, IDisposable {

                #region Attributes

                internal bool m_bEndOperationCalled = false;
                internal bool m_bIsRead;
                internal int m_nReadWritten = 0;
                internal bool m_bCompleted = false;
                internal bool m_bCompletedSynchronously = false;
                internal uint m_nErrorCode = ERROR_SUCCESS;

                private object m_AsyncObject;
                private object m_StateObject;
                private ManualResetEvent m_WaitHandle = new ManualResetEvent(false);
                private AsyncCallback m_Callback;
                private GCHandle m_gchBuffer;

                #endregion Attributes

                #region Properties

                internal bool EndOperationCalled { get { return m_bEndOperationCalled; } }

                public bool IsCompleted { get { return m_bCompleted; } }

                public bool CompletedSynchronously { get { return m_bCompletedSynchronously; } }

                public object AsyncObject { get { return m_AsyncObject; } }

                public object AsyncState { get { return m_StateObject; } }

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

                public AsyncCallback Callback { get { return m_Callback; } }

                #endregion Properties

                #region Constructors

                public SerialAsyncResult(object asyncObject,
                    object stateObject,
                    AsyncCallback callback,
                    bool bIsRead,
                    GCHandle gchBuffer) {

                    m_AsyncObject = asyncObject;
                    m_StateObject = stateObject;
                    m_Callback = callback;
                    m_bIsRead = bIsRead;
                    m_gchBuffer = gchBuffer;
                }

                #endregion Constructors

                #region Methods

                public void Dispose() {
                    m_WaitHandle.Close();
                    m_gchBuffer.Free();
                }

                #endregion Methods
            }

            #endregion Classes

            #region Imports

            [DllImport("kernel32.dll", EntryPoint="CreateFileW",  SetLastError=true,
                CharSet=CharSet.Unicode, ExactSpelling=true)]
            static extern IntPtr CreateFile(string filename, uint access, uint sharemode, uint security_attributes, uint creation, uint flags, uint template);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool CloseHandle(IntPtr handle);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern unsafe bool ReadFile(IntPtr hFile, byte* lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, NativeOverlapped* lpOverlapped);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern unsafe bool WriteFile(IntPtr hFile, byte* lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, NativeOverlapped* lpOverlapped);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool SetCommTimeouts(IntPtr hFile, ref SerialTimeouts lpCommTimeouts);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool SetCommState(IntPtr hFile, ref DCB lpDCB);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool GetCommState(IntPtr hFile, ref DCB lpDCB);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool BuildCommDCB(string def, ref DCB lpDCB);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern int GetLastError();

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool FlushFileBuffers(IntPtr hFile);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool PurgeComm(IntPtr hFile, uint dwFlags);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool EscapeCommFunction(IntPtr hFile, uint dwFunc);

            [DllImport("kernel32.dll", SetLastError=true)]
            static extern bool GetCommModemStatus(IntPtr hFile, out uint modemStat);

            #endregion Imports
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SerialTimeouts {

            #region Attributes

            public int ReadIntervalTimeout;
            public int ReadTotalTimeoutMultiplier;
            public int ReadTotalTimeoutConstant;
            public int WriteTotalTimeoutMultiplier;
            public int WriteTotalTimeoutConstant;

            #endregion Attributes

            #region Constructors

            public SerialTimeouts(int r1, int r2, int r3, int w1, int w2) {
                ReadIntervalTimeout = r1;
                ReadTotalTimeoutMultiplier = r2;
                ReadTotalTimeoutConstant = r3;
                WriteTotalTimeoutMultiplier = w1;
                WriteTotalTimeoutConstant = w2;
            }

            #endregion Constructors

            #region Methods

            public override string ToString() {
                return "ReadIntervalTimeout: " + ReadIntervalTimeout + "\r\n" +
                       "ReadTotalTimeoutMultiplier: " + ReadTotalTimeoutMultiplier + "\r\n" +
                       "ReadTotalTimeoutConstant: " + ReadTotalTimeoutConstant + "\r\n" +
                       "WriteTotalTimeoutMultiplier: " + WriteTotalTimeoutMultiplier + "\r\n" +
                       "WriteTotalTimeoutConstant: " + WriteTotalTimeoutConstant + "\r\n";
            }

            #endregion Methods
        }
    }

    using System;
    using System.IO;
    using System.Threading;

    using LoMaN.IO;

    namespace SerialStreamReader {

        class App {

            // The main serial stream
            static SerialStream ss;

            [STAThread]
            static void Main(string[] args) {

                // Create a serial port
                ss = new SerialStream();
                try {
                    ss.Open("COM3");
                }
                catch (Exception e) {
                    Console.WriteLine("Error: " + e.Message);
                    return;
                }

                // Set port settings
                ss.SetPortSettings(9600);

                // Set timeout so read ends after 20ms of silence after a response
                ss.SetTimeouts(20, 0, 0, 0, 0);

                // Create the StreamWriter used to send commands
                StreamWriter sw = new StreamWriter(ss, System.Text.Encoding.ASCII);

                // Create the Thread used to read responses
                Thread responseReaderThread = new Thread(new ThreadStart(ReadResponseThread));
                responseReaderThread.Start();

                // Read all returned lines
                for (;;) {
                    // Read command from console
                    string command = Console.ReadLine();

                    // Check for exit command
                    if (command.Trim().ToLower() == "exit") {
                        responseReaderThread.Abort();
                        break;
                    }

                    // Write command to modem
                    sw.WriteLine(command);
                    sw.Flush();
                }
            }

            // Main loop for reading responses
            static void ReadResponseThread() {
                StreamReader sr = new StreamReader(ss, System.Text.Encoding.ASCII);
                try {
                    for (;;) {
                        // Read response from modem
                        string response = sr.ReadLine();
                        Console.WriteLine("Response: " + response);
                    }
                }
                catch (ThreadAbortException) {
                }
            }
        }
    }

  • 相关阅读:
    仿MSN小类别滑动效果
    pku1674 Sorting by Swapping
    pku1456 Supermarket
    pku1083 Moving Tables
    pku1125 Stockbroker Grapevine
    pku2232 New StoneForfexCloth Game
    如何低头前进
    和两年前一样
    股票亏了
    早上选举了
  • 原文地址:https://www.cnblogs.com/jhabb/p/1880728.html
Copyright © 2011-2022 走看看