C#字符串表示字节128-255

时间:2017-05-16 12:24:14

标签: .net serial-port

我正在努力重建/改进以前开发的C#/ .NET项目。 串行通信器无法将字节128-255转换为专用字符串。我尝试根据在该项目的工作版本中看到的字符应用Unicode编码。应用编码后,"消息无法发送异常"被扔了。任何关于解决/探究这个问题的指针都非常感激。 感谢。

    public virtual string WriteData(string s, int expectedResponseLength)
    {

        lock (messageLock)
        {
            resetEvent.Reset();
        }

        message = string.Format("WriteData: {0}\r\nMessageType={1}\r\n", s, MessageType.Outgoing);

        expectedLength = expectedResponseLength;

        if (!comPort.IsOpen)
            comPort.Open();


        byte[] bs = new byte[s.Length];
        for (int i = 0; i < s.Length; ++i)
            bs[i] = (byte)s[i];

        for (int i = 0; i < 3; i++)       
        {
            response = string.Empty;
            comPort.Write(bs, 0, bs.Length);

            if (resetEvent.WaitOne(5000))
            {
                return response;
            }
        }

        throw new Exception("Message failed to send.");
    }

    public virtual bool OpenPort()
    {
        try
        {
            if (comPort.IsOpen)
                comPort.Close();
            comPort.Encoding = new UnicodeEncoding();
            comPort.DtrEnable = false;
            comPort.RtsEnable = false;
            comPort.ReceivedBytesThreshold = 1;
            comPort.ReadTimeout = -1;
            comPort.ReadBufferSize = 1024;
            comPort.BaudRate = int.Parse(BaudRate);
            comPort.DataBits = int.Parse(DataBits);
            comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits);
            comPort.PortName = PortName;
            comPort.Open();
            message = string.Concat("OpenPort: ", MessageType.Normal, ", Port opened at ", DateTime.Now);
            return true;
        }
        catch (Exception ex)
        {
            message = "OpenPort: " + MessageType.Error + ex.Message;
            return false;
        }
    }

    private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {

                   string RcvByte = comPort.ReadExisting();

        // Encode the string.
                   byte[] encodedBytes = Encoding.Unicode.GetBytes(RcvByte);


        // Decode bytes back to string.            
                    RcvByte = Encoding.Unicode.GetString(encodedBytes);
                    response += RcvByte;


        lock (messageLock)
        {
            if (response.Length >= expectedLength)
            {
                resetEvent.Set();
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

首先,您需要知道其他设备(您通过串口通信的设备)所需的代码页。理论上它可能是UTF-8(Unicode),但对于较旧的设备,它很可能是一些单字节代码页。例如,对于西欧Windows代码页,它可能是Windows-1252。因此,根据其他设备,您可能需要将comPort.Encoding = new UnicodeEncoding();中的OpenPort更改为以下内容:

comPort.Encoding = new Encoding.GetEncoding(1252);

然后,由于您似乎只与字符串交换(即通信协议中没有二进制数据),请使用SerialPort.Write(String)重载而不是SerialPort.Write(Byte[], Int32, Int32)。如果您正确设置了Encoding属性,前者将负责代码页转换。这意味着您需要删除所有bs数组内容并只需调用

comPort.Write(s);

WriteData方法中。

顺便说一下,如果输入字符串中出现非ASCII字符,则bs填充代码不正确。您最好使用Encoding.GetBytes来获取它:byte[] bs = Encoding.Unicode.GetBytes(s);

SerialPort_DataReceived方法中ReadExisting()将响应读作string,可以使用(再次,如果您已正确设置Encoding属性)。因此,无需使用GetBytes / GetString重新转换,只需设置response

response += comPort.ReadExisting();

您还需要修复代码中的同步。您必须使用lock ...访问response变量,因为它是从两个线程读取和写入的。我还试图确保不同时调用WriteData(未在下面的示例中实现)。

因此,我建议按如下方式重写串口读写方法:

public virtual string WriteData(string s, int expectedResponseLength)
{
    resetEvent.Reset(); // no need to lock this

    expectedLength = expectedResponseLength;

    if (!comPort.IsOpen)
        comPort.Open();

    for (int i = 0; i < 3; i++)       
    {
        lock (messageLock)
        {
            response = string.Empty;
        }
        comPort.Write(s);
        if (resetEvent.WaitOne(5000))
            lock (messageLock)
            {
                return response;
            }
    }

    throw new Exception("Message failed to send.");
}

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    string received = comPort.ReadExisting();
    lock (messageLock)
    {
        response += received;
        if (response.Length >= expectedLength)
        {
            resetEvent.Set();
        }
    }
}

这仍然可能无法保证WriteData返回一些响应而不是抛出"Message failed to send."异常。在协议违规或编码问题的情况下,设备仍然可能不在给定超时内提供请求长度的响应。您需要跟踪ReadExisting()返回的数据以跟踪问题。