如何设置序列特殊字符?

时间:2011-04-11 11:13:04

标签: c# .net serial-port special-characters

在我ongoing quest与某些传统设备接口时,我发现供应商提供的软件将特殊字符设置为:

00 00 00 00 11 13 

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

1A 00 00 1A 11 13 

我想我有两个问题:

  1. 这些字节是什么意思?
  2. 如何告诉SerialPort使用一组特定的特殊字符?
  3. 后者是我真正关心的,但我怀疑前者是有用的。


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

    byte[] specialchars = {
        0x00,
        0x00,
        0x00,
        0x00,
        0x11,
        0x13
    };
    
    this.port.NewLine = System.Text.Encoding.ASCII.GetString(specialchars);
    

    更新2:根据要求,以下是the vendor supplied app的Portmon日志(已过滤以删除数千条IOCTL_SERIAL_GET_COMMSTATUS条目)和my attempt to match even the first exchange

2 个答案:

答案 0 :(得分:2)

NewLine不是您想要的。这是普通的旧“新线”序列,例如仅CR CR或LF。

特殊字符的处理方式如下:

  • EOF - 设置为0x1a,无法在.NET中更改
  • ERR - 由SerialPort.ParityReplace
  • 设置
  • BRK - 不知道
  • EVT - 设置为0x1a,无法在.NET中更改
  • XON - 设置为0x11,你无法在.NET中更改它,甚至通常不会使用sesn
  • XOFF - 设置为0x13,你不能在.NET中更改它,它甚至不会使sesn

您也可以学习Win32 DCB structure。它在内部用于设置串口的状态。

答案 1 :(得分:0)

您可以在c#:

中为serialPort添加扩展名

http://social.msdn.microsoft.com/Forums/vstudio/en-us/89b88e89-5814-4819-8b50-7caa3faf5f54/xonxoff-values-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);
            }