简体   繁体   English

如何设置串行特殊字符?

[英]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: 我想我有两个问题:

  1. What do these bytes mean? 这些字节是什么意思?
  2. How can I tell SerialPort to use a specific set of special characters? 如何告诉SerialPort使用一组特定的特殊字符?

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: 特殊字符的处理方式如下:

  • EOF — set to 0x1a, you cannot change it in .NET EOF —设置为0x1a,您无法在.NET中进行更改
  • ERR — set by SerialPort.ParityReplace ERR —由SerialPort.ParityReplace设置
  • BRK — don't know BRK- 不知道
  • EVT — set to 0x1a, you cannot change it in .NET EVT —设置为0x1a,您无法在.NET中进行更改
  • XON — set to 0x11, you cannot change it in .NET, and it doesn't even usually make sesn XON —设置为0x11,您无法在.NET中进行更改,并且它甚至通常不会使sesn
  • XOFF — set to 0x13, you cannot change it in .NET, and it doesn't even usually make sesn XOFF —设置为0x13,您无法在.NET中进行更改,而且它甚至通常不会使sesn

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM