📄 serialport.cs
字号:
}
if (this.BytesToRead == 0) {
return bytesToRead;
}
}
this.mReadPos = 0;
this.mReadLen = 0;
int topUpBytes = count - bytesToRead;
int bytesRead = 0;
byte[] temp = new byte[topUpBytes];
if (!m_CommAPI.ReadFile(hPort, temp, topUpBytes, ref bytesRead, this.mRxOverlapped)) {
throw new ApplicationException("Read failed");
}
// if (bytesRead != topUpBytes){
// //assert
// }
Buffer.BlockCopy(temp, 0, buffer, offset + bytesToRead, bytesRead);
this.mDecoder = null;
return bytesToRead + bytesRead;
}
/// <summary>
/// Synchronously reads one byte from the OpenNETCF.IO.Ports.SerialPort input buffer.
/// </summary>
/// <returns>The byte that was read.</returns>
public int ReadByte() {
if (!this.IsOpen) {
throw new InvalidOperationException("Port is not open");
}
if (this.mReadLen != this.mReadPos) {
return this.mInBuffer[this.mReadPos++];
}
mDecoder = null;
byte[] temp = new byte[1];
int one = this.Read(temp, 0, 1);
return temp[0];
}
/// <summary>
/// Reads up to the OpenNETCF.IO.Ports.SerialPort.NewLine value in the input buffer.
/// </summary>
/// <returns>A string containing the contents of the input buffer up to the OpenNETCF.IO.Ports.SerialPort.NewLine.</returns>
public string ReadLine() {
return this.ReadTo(this.NewLine);
}
/// <summary>
/// Reads a number of bytes from the OpenNETCF.IO.Ports.SerialPort input buffer and writes those bytes into a character array at a given offset.
/// </summary>
/// <param name="buffer">The character array to which the input is written.</param>
/// <param name="offset">The offset in the buffer array where writing should begin.</param>
/// <param name="count">The number of bytes to be read.</param>
/// <returns></returns>
public int Read(char[] buffer, int offset, int count) {
//TODO Read char[]
throw new NotSupportedException("not yet");
}
/// <summary>
/// Synchronously reads one character from the OpenNETCF.IO.Ports.SerialPort input buffer.
/// </summary>
/// <returns>The character read.</returns>
public int ReadChar() {
//TODO Read single char
throw new NotSupportedException("not yet");
}
/// <summary>
/// Reads a string up to the specified value in the input buffer.
/// </summary>
/// <param name="value">String value where the read operation stops.</param>
/// <returns>A string containing the contents of the input buffer up to the value.</returns>
public string ReadTo(string value) {
//TODO read up to given string
throw new NotSupportedException("not yet");
}
/// <summary>
/// Reads all immediately available characters, based on the encoding, in both the stream and the input buffer of the OpenNETCF.IO.Ports.SerialPort object.
/// </summary>
/// <returns>A string composed of the contents of the stream and the input buffer of the OpenNETCF.IO.Ports.SerialPort object.</returns>
public string ReadExisting() {
//TODO read existing bytes and return string
throw new NotSupportedException("not yet");
}
#endregion
#region Write
/// <summary>
/// Writes a specified count of characters to an output buffer at the specified offset.
/// </summary>
/// <param name="buffer">The character array to which the output is written.</param>
/// <param name="offset">The offset in the buffer array where writing should begin.</param>
/// <param name="count">The number of characters to write.</param>
public void Write(char[] buffer, int offset, int count) {
byte[] bytesFromChars = this.Encoding.GetBytes(buffer, offset, count);
this.Write(bytesFromChars, 0, bytesFromChars.Length);
}
/// <summary>
/// Writes the parameter string to the output.
/// </summary>
/// <param name="str">The string for output.</param>
public void Write(string str) {
byte[] bytesFromString = this.mEncoding.GetBytes(str);
this.Write(bytesFromString, 0, bytesFromString.Length);
}
/// <summary>
/// Writes the specified string and the OpenNETCF.IO.Ports.SerialPort.NewLine value to the output buffer.
/// </summary>
/// <param name="str">The string to be written to output.</param>
public void WriteLine(string str) {
this.Write(str + this.NewLine);
}
/// <summary>
/// Writes a specified count of bytes to an output buffer at the specified offset.
/// </summary>
/// <param name="buffer">The byte array to which the output is written.</param>
/// <param name="offset">The offset in the buffer array where writing should begin.</param>
/// <param name="count">The number of bytes to be write.</param>
public void Write(byte[] buffer, int offset, int count) {
if (!this.IsOpen) {
throw new InvalidOperationException("Port is not open");
}
if (buffer == null) {
throw new ArgumentNullException("buffer");
}
if (offset < 0) {
throw new ArgumentOutOfRangeException("offset must be > 0");
}
if (count < 0) {
throw new ArgumentOutOfRangeException("count must be > 0");
}
if ((buffer.Length - offset) < count) {
throw new ArgumentException("FAILED: ((buffer.Length - offset) < count)");
}
if (buffer.Length == 0) {
return;
}
//if in break don't write
if (this.mInBreak){
throw new ApplicationException("Can't write while in break");
}
byte[] temp = new byte[count];
Buffer.BlockCopy(buffer, offset, temp, 0, count);
//for desktop we should probably be doing other stuff here but if you are in .NET 2.0 you are not using this anyway
int written = 0;
if (!m_CommAPI.WriteFile(hPort, temp, count, ref written, this.mTxOverlapped)){
int er = Marshal.GetLastWin32Error();
if (er == 0x461){
throw new ApplicationException("Write timed out 1");
}
throw new ApplicationException("writefile failed " + er);
}
if (written == 0){
throw new ApplicationException("Write timed out 2");
}
}
#endregion
#endregion
#region Privates
private void CommEventThread() {
CommEventFlags eventFlags = new CommEventFlags();
AutoResetEvent rxevent = new AutoResetEvent(false);
// specify the set of events to be monitored for the port.
bool b;
if(CommAPI.FullFramework) {
b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC);
// set up the overlapped IO
OVERLAPPED o = new OVERLAPPED();
this.mRxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o));
o.Offset = 0;
o.OffsetHigh = 0;
o.hEvent = rxevent.Handle;
Marshal.StructureToPtr(o, this.mRxOverlapped, true);
}
else {
b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE_2);
}
try {
// let Open() know we're started
this.mThreadStarted.Set();
#region >>>> thread loop <<<<
while(hPort != (IntPtr)CommAPI.INVALID_HANDLE_VALUE) {
// wait for a Comm event
if(!m_CommAPI.WaitCommEvent(hPort, ref eventFlags)) {
int e = Marshal.GetLastWin32Error();
if(e == (int)APIErrors.ERROR_IO_PENDING) {
// IO pending so just wait and try again
rxevent.WaitOne();
Thread.Sleep(0);
continue;
}
if(e == (int)APIErrors.ERROR_INVALID_HANDLE) {
// Calling Port.Close() causes hPort to become invalid
// Since Thread.Abort() is unsupported in the CF, we must
// accept that calling Close will throw an error here.
// Close signals the this.mCloseEvent, so wait on it
// We wait 1 second, though Close should happen much sooner
int eventResult = m_CommAPI.WaitForSingleObject(this.mCloseEvent, 1000);
if(eventResult == (int)APIConstants.WAIT_OBJECT_0) {
// the event was set so close was called
hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE;
// reset our ResetEvent for the next call to Open
this.mThreadStarted.Reset();
if(this.mIsOpen) { // this should not be the case...if so, throw an exception for the owner
string error = String.Format("Wait Failed: {0}", e);
throw new ApplicationException(error);
}
return;
}
}
// WaitCommEvent failed
// 995 means an exit was requested (thread killed)
if(e == 995) {
return;
}
else {
string error = String.Format("Wait Failed: {0}", e);
throw new ApplicationException(error);
}
}
// Re-specify the set of events to be monitored for the port.
if(CommAPI.FullFramework) {
m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC);
}
else {
m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE);
}
// Process the flag - extracted main handling into its own method
//ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEvents), eventFlags);
this.ProcessEvents(eventFlags);
} // while(not invalid handle)
#endregion
} // try
catch{
if(this.mRxOverlapped != IntPtr.Zero)
LocalFree(this.mRxOverlapped);
throw;
}
}
private Decoder GetDecoder(){
if (mDecoder == null){
this.mDecoder = mEncoding.GetDecoder();
}
return mDecoder;
}
private void ProcessEvents(object flags){
CommEventFlags eventFlags = (CommEventFlags)flags;
// check the event for errors
#region >>>> error checking <<<<
if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) {
CommErrorFlags errorFlags = new CommErrorFlags();
CommStat commStat = new CommStat();
// get the error status
if(!m_CommAPI.ClearCommError(hPort, ref errorFlags, commStat)) {
// ClearCommError failed!
string error = String.Format("ClearCommError Failed: {0}", Marshal.GetLastWin32Error());
throw new ApplicationException(error);
}
if(((uint)errorFlags & (uint)CommErrorFlags.BREAK) != 0) {
// BREAK can set an error, so make sure the BREAK bit is set an continue
eventFlags |= CommEventFlags.BREAK;
}
else {
// we have an error. Build a meaningful string and throw an exception
if (ErrorReceived != null){
if ((errorFlags & CommErrorFlags.TXFULL) != 0) {
ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.TXFull));
}
if ((errorFlags & CommErrorFlags.RXOVER) != 0) {
ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.RXOver));
}
if ((errorFlags & CommErrorFlags.OVERRUN) != 0) {
ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.Overrun));
}
if ((errorFlags & CommErrorFlags.RXPARITY) != 0) {
ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.RXParity));
}
if ((errorFlags & CommErrorFlags.FRAME) != 0) {
ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.Frame));
}
}
return;
}
} // if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0)
#endregion
#region >>>> Receive data subsection <<<<
// check for RXCHAR
if (DataReceived != null){
if((eventFlags & CommEventFlags.RXCHAR) != 0) {
DataReceived(this,new SerialDataReceivedEventArgs(SerialData.Chars));
}
if(((uint)eventFlags & 2) != 0) {
DataReceived(this,new SerialDataReceivedEventArgs(SerialData.Eof));
}
}
#endregion
#region >>>> line status checking <<<<
if(PinChanged != null){
// check the CTS
if(((uint)eventFlags & (uint)CommEventFlags.CTS) != 0) {
PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.CtsChanged));
}
// check the DSR
if(((uint)eventFlags & (uint)CommEventFlags.DSR) != 0) {
PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.DsrChanged));
}
// check for a RING
if(((uint)eventFlags & (uint)CommEventFlags.RING) != 0) {
PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.Ring));
}
// check for a RLSD
if(((uint)eventFlags & (uint)CommEventFlags.RLSD) != 0) {
PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.CDChanged));
}
// check for a break
if(((uint)eventFlags & (uint)CommEventFlags.BREAK) != 0) {
PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.Break));
}
}
#endregion
}
private bool UpdateSettings() {
if(!this.mIsOpen) return false;
m_CommAPI.PurgeComm(hPort,0x4 | 0x8);
bool outX = false;
bool inX = false;
bool outCts = false;
byte rtsCtrl = 0x01;
if (mHandshake != Handshake.None){
if (mHandshake == Handshake.RequestToSend || mHandshake == Handshake.RequestToSendXOnXOff){
//outCts = true; by design
rtsCtrl = 0x02;
}else if (this.mRts == 0){
rtsCtrl = 0x00;
}
if (mHandshake == Handshake.XOnXOff || mHandshake == Handshake.RequestToSendXOnXOff){
outX = true;
inX = true;
}
}
// transfer the port settings to a DCB structure
m_CommAPI.GetCommState(hPort, this.mDcb);
this.mDcb.BaudRate = (uint)mBaudRate;
this.mDcb.ByteSize = this.mByteSize;
this.mDcb.EofChar = 0;// (sbyte)0x04;
this.mDcb.ErrorChar = (sbyte)mErrorChar;
this.mDcb.EvtChar = (sbyte)0x00;
this.mDcb.fAbortOnError = false;
this.mDcb.fBinary = true;
this.mDcb.fDsrSensitivity = false;
this.mDcb.fDtrControl = (byte)this.mDtr;
this.mDcb.fErrorChar = (this.mDcb.ErrorChar != 0);
this.mDcb.fInX = inX;
this.mDcb.fNull = this.mDiscardNull;
this.mDcb.fOutX = outX;
this.mDcb.fOutxCtsFlow = outCts;
this.mDcb.fOutxDsrFlow = false;
this.mDcb.fParity = (mParity == Parity.None) ? false : true;
this.mDcb.fRtsControl = rtsCtrl;
this.mDcb.fTXContinueOnXoff = true;
this.mDcb.Parity = (byte)mParity;
this.mDcb.StopBits = (byte)this.mStopBits;
this.mDcb.XoffChar = (sbyte)0x13; //ASCII.DC3;
this.mDcb.XonChar = (sbyte)0x11; //ASCII.DC1;
this.mDcb.XonLim = this.mDcb.XoffLim = 0;//(ushort)(this.mRxBufferSize / 10);
// store some state variables
this.mDtr = this.mDcb.fDtrControl == 0x01 ? 1 : 0;
this.mRts = this.mDcb.fRtsControl == 0x01 ? 1 : 0;
return m_CommAPI.SetCommState(hPort, this.mDcb);
}
private void UpdateTimeouts(){
// set the Comm timeouts
CommTimeouts ct = new CommTimeouts();
// reading we'll return immediately
// this doesn't seem to work as documented
ct.ReadIntervalTimeout = 0xffffffff;
if (this.mReadTimeout > 0){
ct.ReadTotalTimeoutConstant = (uint)this.mReadTimeout;
ct.ReadTotalTimeoutMultiplier = 0;
}else{
ct.ReadTotalTimeoutConstant = 0;
ct.ReadTotalTimeoutMultiplier = 0;
}
uint writeTimeoutOrZero;
if (mWriteTimeout == InfiniteTimeout){
writeTimeoutOrZero = 0;
}else{
writeTimeoutOrZero = (uint)mWriteTimeout;
}
ct.WriteTotalTimeoutConstant = writeTimeoutOrZero;
ct.WriteTotalTimeoutMultiplier = 0;
m_CommAPI.SetCommTimeouts(hPort, ct);
}
[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);
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -