0

我正在研究串行通信协议。在这个协议中,packt 由字节组成,它应该以 . 开头和结尾0x7E

该协议指示任何被0x7E0x7D应该被转义到0x7D 0x5E0x7d 0x5D相应地转义的字节。

这是一个示例数据包:

7E 40 09 00 BE EF 05 7E 06 01 02 03 04 05 7E

如您所见,byte[7]在此数据包中应替换为 2 个字节0x7D 0x5E。为此,我编写了以下方法,但无法完成此任务:

private List<byte> Finalize(List<byte> packet)
{
    int u = 1; //keep track of end of pack
    //because if escape characters are present
    //end bit will be shifted to right

    //Walk through list and fix escape bytes
    for (int i = 1; i < packet.Count; i++)
    {
        if (packet[i] == 0x7D)
        {
            packet[u] = 0x7D;
            packet[u + 1] = 0x5D;
            u += 2;
        }
        else if (packet[i] == 0x7E) //Sync Byte
        {
            packet[u] = 0x7D;
            packet[u + 1] = 0x5E;
            u += 2;
        }
        else
        {
           packet[u] = packet[i]; //Exception here!!
           u++;
        }
    }

    return packet;
}

该方法抛出一个ArgumentOutOfRangeException. 有人可以告诉我可能是什么问题!?我想我实现了一个正确的逻辑,但似乎我没有正确处理索引!

循环从索引 1 开始,因为它是起始字节,不应更改。它也不应该更改列表中的最后一个字节,即 0x7E,即结束字节!

4

4 回答 4

2

我建议创建一个新列表,并将数据从原始列表复制到新列表。虽然可能有一些方法可以“就地”进行更新,但简单地创建一个新列表可能更容易。实际上,使用 abyte[]而不是List<byte>可能会更好,尽管您必须在创建新数组之前计算原始数组中 7D 或 7E 字符的数量。

于 2012-10-16T23:21:08.150 回答
1

首先,当您用值 0x7D0x7E. 其次,您的更改u速度比i产生上述异常的速度要快。当您转义字节时,您将 2 添加到u但在循环的该迭代中for, i 仅增加。第三,更好的方法肯定是while循环。

要处理第一个问题,您应该向列表中添加更多元素。Insert会做到这一点,而不是手动将所有内容向右移动。第二个问题可以通过只使用一个计数器来解决。检查代码:

        private List<byte> Finalize(List<byte> packet)
        {
            int i = 1;
            while (i < packet.Count-1)
            {
                if (packet[i] == 0x7D)
                {
                    packet[i] = 0x7D;
                    packet.Insert(i+1, 0x5D);
                    i += 2;
                }
                else if (packet[i] == 0x7E) //Sync Byte
                {
                    packet[i] = 0x7D;
                    packet.Insert(i+1, 0x5E);
                    i += 2;
                }
                else 
                    i++;
            }
            return packet;
       }

另一种解决方案是在方法中创建新列表并为其添加适当的值。 while (i < packet.Count-1)是因为我认为您不想逃避结束字节。请记住,列表中的最后一个字节packet[packet.Count-1]不是packet[packet.Count]

于 2012-10-16T23:38:52.273 回答
1

这是一个扩展方法,它转义数据包。它不触及默认的第一个和最后一个字节。

public static IEnumerable<byte> Finalize(this IList<byte> packet)
{
    yield return 0x7E;

    for(int i = 1; i < packet.Count - 1; i++)
    {
        if (packet[i] == 0x7E)
        {
            yield return 0x7D;
            yield return 0x5E;
            continue;
        }

        if (packet[i] == 0x7D)
        {
            yield return 0x7D;
            yield return 0x5D;
            continue;
        }

        yield return packet[i];
    }

    yield return 0x7E;
}

用法很简单:

byte[] packet = { 0x7E, 0x40, 0x09, 0xEF, 0x05, 0x7E, 0x06, 0x04, 0x05, 0x7E };
byte[] escapedPacket = packet.Finalize().ToArray();
于 2012-10-17T00:20:24.470 回答
0

我对 c# 不太熟悉,但看起来你正在覆盖源数据包,并在你进行时破坏它。

另外,List 会自动增长吗?因为你写的超出了它的长度。List 是如何处理的?

循环应该从 1 还是 0 开始?因为您的退出条件是“i < packet.Count”而不是“i <= packet.Count”,它会错过最后一个字节。

于 2012-10-16T23:29:40.223 回答