[英]How do I set serial special characters?
In my ongoing quest to interface with some legacy equipment, I've discovered that the vendor supplied software sets the special characters to: 在与一些旧设备进行交互的不断探索中,我发现供应商提供的软件将特殊字符设置为:
00 00 00 00 11 13
But the SerialPort class of .NET set them to: 但是.NET的SerialPort类将它们设置为:
1A 00 00 1A 11 13
I suppose that I have two questions: 我想我有两个问题:
The latter is all I really care about, but I suspect the former is going to be useful to know. 后者是我真正关心的,但是我怀疑前者会很有用。
Update: The following doesn't work: 更新:以下内容无效:
byte[] specialchars = {
0x00,
0x00,
0x00,
0x00,
0x11,
0x13
};
this.port.NewLine = System.Text.Encoding.ASCII.GetString(specialchars);
Update 2: As requested, here are Portmon logs for the vendor supplied app (filtered to remove the many thousands of IOCTL_SERIAL_GET_COMMSTATUS entries) and for my attempt to match even the first exchange . 更新2:根据要求,以下是供应商提供的应用程序的 Portmon日志(经过过滤以删除成千上万的IOCTL_SERIAL_GET_COMMSTATUS条目),以及我尝试匹配的第一个 Exchange日志。
NewLine
is not what you are looking for. NewLine
不是您想要的。 It's the plain old 'new line' sequence, eg CR LF or LF alone. 这是普通的旧“换行”序列,例如CR LF或LF单独。
The special characters are handled like this: 特殊字符的处理方式如下:
SerialPort.ParityReplace
SerialPort.ParityReplace
设置 It may be helpful for you to study the Win32 DCB structure as well. 研究Win32 DCB结构也可能对您有所帮助。 It's used by .NET internally to set the state of the serial port.
.NET在内部使用它设置串行端口的状态。
You can add an extenstion to the serialPort in c# : 您可以在c#中将扩展添加到serialPort中:
http://social.msdn.microsoft.com/Forums/vstudio/en-us/89b88e89-5814-4819-8b50-7caa3faf5f54/xonxoff-values-in-net20-serialport-class?forum=csharpgeneral http://social.msdn.microsoft.com/Forums/vstudio/en-us/89b88e89-5814-4819-8b50-7caa3faf5f54/xonxoff-values-in-net20-serialport-class?forum=csharpgeneral
for the other fields you can change : 对于其他字段,您可以更改:
dcbType.GetField("XonChar");
dcbType.GetField(“ XonChar”); // "XonChar", "XoffChar", "ErrorChar", "EofChar", "EvtChar"
//“ XonChar”,“ XoffChar”,“ ErrorChar”,“ EofChar”,“ EvtChar”
Code : 代码:
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 a p/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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.