如何设置序列特殊字符?
在我不断寻求与某些传统设备接口的过程中,我发现供应商提供的软件将特殊字符设置为:
00 00 00 00 11 13
但.NET的SerialPort类将它们设置为:
1A 00 00 1A 11 13
我想我有两个问题:
- 这些字节意味着什么?
- 如何告诉SerialPort使用一组特定的特殊字符?
后者是我真正关心的,但我怀疑前者是有用的知道。
更新:以下不起作用:
byte[] specialchars = { 0x00, 0x00, 0x00, 0x00, 0x11, 0x13 }; this.port.NewLine = System.Text.Encoding.ASCII.GetString(specialchars);
更新2:根据要求,这里是供应商提供的应用程序的 Portmon日志(已过滤以删除数千个IOCTL_SERIAL_GET_COMMSTATUS条目)以及我尝试匹配第一个交换 。
NewLine
不是您想要的。 这是普通的旧“新线”序列,例如CR LF或LF。
特殊字符的处理方式如下:
- EOF – 设置为0x1a,您无法在.NET中更改它
- ERR – 由
SerialPort.ParityReplace
设置 - BRK – 不知道
- EVT – 设置为0x1a,您无法在.NET中更改它
- XON – 设置为0x11,你不能在.NET中更改它,它甚至通常不会生成sesn
- XOFF – 设置为0x13,你不能在.NET中更改它,它甚至通常不会生成sesn
研究Win32 DCB结构可能对您有所帮助。 .NET内部用它来设置串口的状态。
您可以在c#中向serialPort添加扩展:
对于其他字段,您可以更改:
dcbType.GetField( “XonChar”); //“XonChar”,“XoffChar”,“ErrorChar”,“EofChar”,“EvtChar”
代码:
using System; using System.ComponentModel; using System.IO.Ports; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using Microsoft.Win32.SafeHandles; class Program { static void Main(string[] args) { using (var port = new SerialPort("COM1")) { port.Open(); port.SetXonXoffChars(0x12, 0x14); } } } internal static class SerialPortExtensions { [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] public static void SetXonXoffChars(this SerialPort port, byte xon, byte xoff) { if (port == null) throw new NullReferenceException(); if (port.BaseStream == null) throw new InvalidOperationException("Cannot change X chars until after the port has been opened."); try { // Get the base stream and its type which is System.IO.Ports.SerialStream object baseStream = port.BaseStream; Type baseStreamType = baseStream.GetType(); // Get the Win32 file handle for the port SafeFileHandle portFileHandle = (SafeFileHandle)baseStreamType.GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(baseStream); // Get the value of the private DCB field (a value type) FieldInfo dcbFieldInfo = baseStreamType.GetField("dcb", BindingFlags.NonPublic | BindingFlags.Instance); object dcbValue = dcbFieldInfo.GetValue(baseStream); // The type of dcb is Microsoft.Win32.UnsafeNativeMethods.DCB which is an internal type. We can only access it through reflection. Type dcbType = dcbValue.GetType(); dcbType.GetField("XonChar").SetValue(dcbValue, xon); dcbType.GetField("XoffChar").SetValue(dcbValue, xoff); // We need to call SetCommState but because dcbValue is a private type, we don't have enough // information to create ap/Invoke declaration for it. We have to do the marshalling manually. // Create unmanaged memory to copy DCB into IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(dcbValue)); try { // Copy their DCB value to unmanaged memory Marshal.StructureToPtr(dcbValue, hGlobal, false); // Call SetCommState if (!SetCommState(portFileHandle, hGlobal)) throw new Win32Exception(Marshal.GetLastWin32Error()); // Update the BaseStream.dcb field if SetCommState succeeded dcbFieldInfo.SetValue(baseStream, dcbValue); } finally { if (hGlobal != IntPtr.Zero) Marshal.FreeHGlobal(hGlobal); } } catch (SecurityException) { throw; } catch (OutOfMemoryException) { throw; } catch (Win32Exception) { throw; } catch (Exception ex) { throw new ApplicationException("SetXonXoffChars has failed due to incorrect assumptions about System.IO.Ports.SerialStream which is an internal type.", ex); } } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SetCommState(SafeFileHandle hFile, IntPtr lpDCB); }