如何设置序列特殊字符?

发布于 2024-10-31 10:31:31 字数 867 浏览 1 评论 0 原文

在我不断追求与一些旧设备交互时,我发现供应商提供的软件将特殊字符设置为:

00 00 00 00 11 13 

但是 .NET 的 SerialPort 类将它们设置为:

1A 00 00 1A 11 13 

我想我有两个问题:

  1. 这些字节是什么意思?
  2. 如何告诉 SerialPort 使用一组特定的特殊字符?

我真正关心的是后者,但我怀疑了解前者会很有用。


更新:以下内容不起作用:

byte[] specialchars = {
    0x00,
    0x00,
    0x00,
    0x00,
    0x11,
    0x13
};

this.port.NewLine = System.Text.Encoding.ASCII.GetString(specialchars);

更新 2:根据要求,以下是 供应商提供的应用(经过过滤以删除数千个 IOCTL_SERIAL_GET_COMMSTATUS 条目)和 我尝试匹配第一次交换

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:

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?

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

莫言歌 2024-11-07 10:31:31

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 在内部使用它来设置串行端口的状态。

NewLine is not what you are looking for. It's the plain old 'new line' sequence, e.g. CR LF or LF alone.

The special characters are handled like this:

  • EOF — set to 0x1a, you cannot change it in .NET
  • ERR — set by SerialPort.ParityReplace
  • BRK — don't know
  • EVT — set to 0x1a, you cannot change it in .NET
  • XON — set to 0x11, you cannot change it in .NET, and it doesn't even usually make sesn
  • XOFF — set to 0x13, you cannot change it in .NET, and it doesn't even usually make sesn

It may be helpful for you to study the Win32 DCB structure as well. It's used by .NET internally to set the state of the serial port.

烂柯人 2024-11-07 10:31:31

您可以在 c# 中向串行端口添加扩展:

http://social.msdn.microsoft.com/Forums/vstudio/en-us/89b88e89-5814-4819-8b50-7caa3faf5f54/xonxoff- value-in-net20-serialport-class?forum=csharpgeneral

对于您可以更改的其他字段:

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 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);
            }

You can add an extenstion to the serialPort in c# :

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"); // "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);
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文