前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >短信收发类无错版SerialStream.cs

短信收发类无错版SerialStream.cs

作者头像
Java架构师必看
发布2020-10-26 11:04:55
8250
发布2020-10-26 11:04:55
举报
文章被收录于专栏:Java架构师必看

/* *Author:MarcusLorentzon,2001 *        d98m

强烈推介IDEA2020.2破解激活,IntelliJ IDEA 注册码,2020.2 IDEA 激活码

/*  * Author: Marcus Lorentzon, 2001  *         d98malor@dtek.chalmers.se  *  * 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 override long Length {    get {     throw new NotSupportedException("Length isn't supported on serial ports.");    }   }

  public override long Position {    get {     throw new NotSupportedException("Seek isn't supported on serial ports.");    }    set {     throw new NotSupportedException("Seek isn't supported on serial ports.");    }   }

  public bool Dtr {    set {     if (!EscapeCommFunction(m_hFile, value ? SETDTR : CLRDTR)) {      throw new Win32Exception();     }    }   }

  public bool Rts {    set {     if (!EscapeCommFunction(m_hFile, value ? SETRTS : CLRRTS)) {      throw new Win32Exception();     }    }   }

  public bool Break {    set {     if (!EscapeCommFunction(m_hFile, value ? SETBREAK : CLRBREAK)) {      throw new Win32Exception();     }    }   }

  public bool Cts {    get {     uint status;     if (!GetCommModemStatus(m_hFile, out status)) {      throw new Win32Exception();     }     return (status & MS_CTS_ON) > 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 << 1) | (value << 1); } }    public uint fOutxCtsFlow { get { return (Flags>>2)&1; }           set { Flags = Flags & ~(1U << 2) | (value << 2); } }    public uint fOutxDsrFlow { get { return (Flags>>3)&1; }           set { Flags = Flags & ~(1U << 3) | (value << 3); } }    public uint fDtrControl { get { return (Flags>>4)&3; }           set { Flags = Flags & ~(3U << 4) | (value << 4); } }    public uint fDsrSensitivity { get { return (Flags>>6)&1; }           set { Flags = Flags & ~(1U << 6) | (value << 6); } }    public uint fTXContinueOnXoff { get { return (Flags>>7)&1; }           set { Flags = Flags & ~(1U << 7) | (value << 7); } }    public uint fOutX { get { return (Flags>>8)&1; }           set { Flags = Flags & ~(1U << 8) | (value << 8); } }    public uint fInX { get { return (Flags>>9)&1; }           set { Flags = Flags & ~(1U << 9) | (value << 9); } }    public uint fErrorChar { get { return (Flags>>10)&1; }           set { Flags = Flags & ~(1U << 10) | (value << 10); } }    public uint fNull { get { return (Flags>>11)&1; }           set { Flags = Flags & ~(1U << 11) | (value << 11); } }    public uint fRtsControl { get { return (Flags>>12)&3; }           set { Flags = Flags & ~(3U << 12) | (value << 12); } }    public uint fAbortOnError { get { return (Flags>>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  } }

本文由来源 21aspnet,由 system_mush 整理编辑,其版权均为 21aspnet 所有,文章内容系作者个人观点,不代表 Java架构师必看 对观点赞同或支持。如需转载,请注明文章来源。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档