📄 port.cs
字号:
//==========================================================================================
//
// WJ.Serial.Port
// Copyright (c) 2006, WJ Communications, Inc.
//
// This class is mostly derived from the OpenNETCF.org Serial Port class.
//
// (OpenNETCF.IO.Serial.Port as of 02/14/05)
// Some modifications were made to the original source, however, including:
// 1) Changed Assembly namespace to WJ.Serial
// 2) Added IsOpenChanged to report changes in a ports "IsOpen" property
// 3) Removed "CommCapabilities" the ability to retrieve a port's capabilities
// 4) Windows Port Names are prepended with \\.\ (eg \\.\COM3)
// 5) Opening a port that is already open returns true instead of false
// 6) Closing a port that is not open returns true instead of false
// 7) sthreshold is ignored => the whole parameter to Output is sent immediately
// 8) Win32 Errors processed slightly different in Thread Loop.
// a) switch instead of if...then constructs
// b) on APIErrors.ERROR_INVALID_HANDLE errors,
// if the port is still open
// it is closed and an IsOpenChanged event is fired,
// instead of a CommPortException being thrown.
// c) on APIErrors.ERROR_OPERATION_ABORTED (995) errors,
// the port is closed and an IsOpenChanged event is fired,
// instead of nothing happening.
//
//==========================================================================================
//==========================================================================================
//
// OpenNETCF.IO.Serial.Port
// Copyright (c) 2003, OpenNETCF.org
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the OpenNETCF.org Shared Source License.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the OpenNETCF.org Shared Source License
// for more details.
//
// You should have received a copy of the OpenNETCF.org Shared Source License
// along with this library; if not, email licensing@opennetcf.org to request a copy.
//
// If you wish to contact the OpenNETCF Advisory Board to discuss licensing, please
// email licensing@opennetcf.org.
//
// For general enquiries, email enquiries@opennetcf.org or visit our website at:
// http://www.opennetcf.org
//
//==========================================================================================
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Text;
using System.Collections;
namespace WJ.Serial
{
/// <summary>
/// Exceptions throw by the OpenNETCF.IO.Serial class
/// </summary>
public class CommPortException : Exception
{
/// <summary>
/// Default CommPortException
/// </summary>
/// <param name="desc"></param>
public CommPortException(string desc) : base(desc) {}
}
/// <summary>
/// A class wrapper for serial port communications.
/// Derived from OpenNETCF.org's : OpenNETCF.IO.Serial.Port
/// See the Source Code for more documentation, and differences to original OpenNETCF source.
/// </summary>
public class Port : IDisposable
{
[DllImport("kernel32", EntryPoint="LocalAlloc", SetLastError=true)]
internal static extern IntPtr LocalAlloc(int uFlags, int uBytes);
[DllImport("kernel32", EntryPoint="LocalFree", SetLastError=true)]
internal static extern IntPtr LocalFree(IntPtr hMem);
#region delegates and events
/// <summary>
/// Raised on all enabled communication events
/// </summary>
public delegate void CommEvent();
/// <summary>
/// Raised when the communication state changes
/// </summary>
public delegate void CommChangeEvent(bool NewState);
/// <summary>
/// Raised during any communication error
/// </summary>
public delegate void CommErrorEvent(string Description);
/// <summary>
/// A communication error has occurred
/// </summary>
public event CommErrorEvent OnError;
/// <summary>
/// Serial data has been received
/// </summary>
public event CommEvent DataReceived;
// /// <summary>
// /// Overrun of the transmit buffer
// /// </summary>
// public event CommEvent RxOverrun;
/// <summary>
/// Transmit complete
/// </summary>
public event CommEvent TxDone;
/// <summary>
/// Set flag character was in the receive stream
/// </summary>
public event CommEvent FlagCharReceived;
/// <summary>
/// Power change event has occurred
/// </summary>
public event CommEvent PowerEvent;
/// <summary>
/// Serial buffer's high-water level has been exceeded
/// </summary>
public event CommEvent HighWater;
/// <summary>
/// DSR state has changed
/// </summary>
public event CommChangeEvent DSRChange;
/// <summary>
/// Ring signal has been detected
/// </summary>
public event CommChangeEvent RingChange;
/// <summary>
/// CTS state has changed
/// </summary>
public event CommChangeEvent CTSChange;
/// <summary>
/// RLSD state has changed
/// </summary>
public event CommChangeEvent RLSDChange;
/// <summary>
/// COM port "open" status has changed
/// </summary>
public event CommChangeEvent IsOpenChanged;
#endregion
#region ##### variable declarations #####
private string portName;
private IntPtr hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE;
// default Rx buffer is 1024 bytes
private int rxBufferSize = 1024;
private Queue rxFIFO;
private int rthreshold = 1;
// default Tx buffer is 1024 bytes
private int txBufferSize = 1024;
private byte[] txBuffer;
private int ptxBuffer = 0;
private int sthreshold = 1;
private Mutex rxBufferBusy = new Mutex();
private int inputLength;
private DCB dcb = new DCB();
private DetailedPortSettings portSettings;
private Thread eventThread;
private ManualResetEvent threadStarted = new ManualResetEvent(false);
private IntPtr closeEvent;
private string closeEventName = "CloseEvent";
private int rts = 0;
private bool rtsavail = false;
private int dtr = 0;
private bool dtravail = false;
private int brk = 0;
private int setir = 0;
// private bool isOpen = false;
private IntPtr txOverlapped = IntPtr.Zero;
private IntPtr rxOverlapped = IntPtr.Zero;
private CommAPI m_CommAPI;
#endregion
private void Init()
{
// create the API class based on the target
if (System.Environment.OSVersion.Platform != PlatformID.WinCE)
m_CommAPI=new WinCommAPI();
else
m_CommAPI=new CECommAPI();
// create a system event for synchronizing Closing
closeEvent = m_CommAPI.CreateEvent(true, false, closeEventName);
rxFIFO = new Queue(rxBufferSize);
txBuffer = new byte[txBufferSize];
portSettings = new DetailedPortSettings();
}
#region constructors
/// <summary>
/// Create a serial port class. The port will be created with defualt settings.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
public Port(string PortName)
{
this.PortName = PortName;
Init();
}
/// <summary>
/// Create a serial port class.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
/// <param name="InitialSettings">BasicPortSettings to apply to the new Port</param>
public Port(string PortName, BasicPortSettings InitialSettings)
{
this.PortName = PortName;
Init();
//override default ettings
portSettings.BasicSettings = InitialSettings;
}
/// <summary>
/// Create a serial port class.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
/// <param name="InitialSettings">DetailedPortSettings to apply to the new Port</param>
public Port(string PortName, DetailedPortSettings InitialSettings)
{
this.PortName = PortName;
Init();
//override default ettings
portSettings = InitialSettings;
}
/// <summary>
/// Create a serial port class.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
/// <param name="RxBufferSize">Receive buffer size, in bytes</param>
/// <param name="TxBufferSize">Transmit buffer size, in bytes</param>
public Port(string PortName, int RxBufferSize, int TxBufferSize)
{
rxBufferSize = RxBufferSize;
txBufferSize = TxBufferSize;
this.PortName = PortName;
Init();
}
/// <summary>
/// Create a serial port class.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
/// <param name="InitialSettings">BasicPortSettings to apply to the new Port</param>
/// <param name="RxBufferSize">Receive buffer size, in bytes</param>
/// <param name="TxBufferSize">Transmit buffer size, in bytes</param>
public Port(string PortName, BasicPortSettings InitialSettings, int RxBufferSize, int TxBufferSize)
{
rxBufferSize = RxBufferSize;
txBufferSize = TxBufferSize;
this.PortName = PortName;
Init();
//override default ettings
portSettings.BasicSettings = InitialSettings;
}
/// <summary>
/// Create a serial port class.
/// </summary>
/// <param name="PortName">The port to open (i.e. "COM1:")</param>
/// <param name="InitialSettings">DetailedPortSettings to apply to the new Port</param>
/// <param name="RxBufferSize">Receive buffer size, in bytes</param>
/// <param name="TxBufferSize">Transmit buffer size, in bytes</param>
public Port(string PortName, DetailedPortSettings InitialSettings, int RxBufferSize, int TxBufferSize)
{
rxBufferSize = RxBufferSize;
txBufferSize = TxBufferSize;
this.PortName = PortName;
Init();
//override default ettings
portSettings = InitialSettings;
}
#endregion
// since the event thread blocks until the port handle is closed
// implement both a Dispose and destrucor to make sure that we
// clean up as soon as possible
/// <summary>
/// Dispose the object's resources
/// </summary>
public void Dispose()
{
if(isOpen)
this.Close();
}
/// <summary>
/// Class destructor
/// </summary>
~Port()
{
if(isOpen)
this.Close();
}
/// <summary>
/// The name of the Port (i.e. "COM1:")
/// </summary>
public string PortName
{
get
{
return portName;
}
set
{
if(! CommAPI.FullFramework)
{
portName = value;
// for CE, ensure the port name is colon terminated "COMx:"
if(! value.EndsWith(":"))
{
portName += ":";
}
}
else
{
// some windows funniness... COM ports are preceeded by \\.\?
portName = "\\\\.\\" + value;
}
}
}
/// <summary>
/// Returns whether or not the port is currently open
/// </summary>
public bool IsOpen
{
get
{
return isOpen;
}
}
private bool isOpenInternal = false;
/// <summary>
/// Internal private property used to generate IsOpenChanged events when a port is opened or closed.
/// </summary>
private bool isOpen
{
get { return isOpenInternal; }
set
{
if (value != isOpenInternal)
{
isOpenInternal = value;
if (IsOpenChanged != null)
IsOpenChanged(value);
}
}
}
/// <summary>
/// Open the current port
/// </summary>
/// <returns>true if successful, false if it fails</returns>
public bool Open()
{
if (isOpen)
return true; // Was false in OpenNETCF.IO.Serial.Port
if(CommAPI.FullFramework)
{
// set up the overlapped tx IO
// AutoResetEvent are = new AutoResetEvent(false);
OVERLAPPED o = new OVERLAPPED();
txOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o));
o.Offset = 0;
o.OffsetHigh = 0;
o.hEvent = IntPtr.Zero;
Marshal.StructureToPtr(o, txOverlapped, true);
}
hPort = m_CommAPI.CreateFile(portName);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -