考虑以下C ++代码,它通过RS232将数据发送到设备。
strcpy(m_MsgBytes, "SRT1");
iTmp = finalizeNL20Message(m_MsgBytes, 4);
int CVTSSLTNL20Message::finalizeNL20Message(BYTE *pMsgData, int iInLen)
{
BYTE ucMsg[MAX_MESSAGE_LENGTH];
ucMsg[0] = MSG_STX; // 0x02
ucMsg[1] = NL20_BLOCK_ID; // ox01
ucMsg[2] = ATTR_CMD; // 'C'
memcpy(&ucMsg[3], pMsgData, iInLen);
ucMsg[3 + iInLen] = MSG_ETX;
ucMsg[4 + iInLen] = calculateNL20Checksum(ucMsg, 4 + iInLen);
ucMsg[5 + iInLen] = MSG_CR;
ucMsg[6 + iInLen] = MSG_LF;
memcpy(pMsgData, ucMsg, 7 + iInLen);
return 7 + iInLen;
}
BYTE CVTSSLTNL20Message::calculateNL20Checksum(const BYTE *pData, int iInLen)
{
BYTE ucChk = 0;
for (int iCnt = 0; iCnt < iInLen; iCnt++)
ucChk = ucChk ^ pData[iCnt];
return ucChk;
}
我用C#重写了这段代码:
public static string Generate()
{
return RIONNLHelper.FinalizeMessage("SRT1");
}
public static string FinalizeMessage(string data)
{
//STX=0x02 NL20BLOCKID=0x01 Command=C (Command from computer)
data = "\x02\x01C" + data;
//ETX=0x03
data += "\x03";
data += (char)calculateNL20CheckSum(data);
data += "\r\n";
return data;
}
public static byte calculateNL20CheckSum(string data)
{
byte chk = 0;
foreach (byte b in Encoding.ASCII.GetBytes(data))
{
chk ^= b;
}
return chk;
}
在发送
之前,字符串将转换为字节数组bytes = data.Select(c =&gt;(byte)c)。ToArray(); 现在的问题是C#代码永远不会从设备上获得这些请求的响应。它确实将其他数据发送回波特率以及所有正确的数据。
我对从C ++代码中转换缓冲区有些怀疑。 0x020x01C数据0x03校验和\ r \ n
成了
\ x02 \ x01C data \ x03 checksum \ r \ n
否则校验和计算的重写是否正确?首先计算字节的校验和,然后转换回char
答案 0 :(得分:2)
这是一个奇怪的。和往常一样,我创建了一个单元测试。然后我使用C ++ CLR构建了C ++版本,并通过测试将输出与输入“SRT1”进行比较。最初,它失败了
C++ version: 02 01 43 53 52 54 31 03 27 0d 0a
C# version: 02 1c 53 52 54 31 03 79 0d 0a
那1C看起来很熟悉......
错误似乎是假设字符串"\x02\x01C" + data
;与"\x02" + "\x01" + "C" + data;
相同,而十六进制转义将继续解释数字,直到找到不是十六进制数字的字符。所以'C'成为十字转义的一部分。
分解文字允许解析器将'C'解析为单独的字符,然后单元测试通过。
答案 1 :(得分:1)
嗯......你的问题可能是某些代码使用Encoding.ASCII.GetBytes(finalString)
最终将string
转换为byte[]
,但校验和可能是&gt; = 0x7F,所以非ASCII字符。在string
之后手动将byte[]
转换为Generate
:
string result = Generate();
byte[] bytes = new byte[result.Length];
for (int i = 0; i < result.Length; i++)
{
bytes[i] = (byte)result[i];
}
只是为了确保改变:
foreach (byte b in Encoding.ASCII.GetBytes(data))
{
chk ^= b;
到
foreach (char ch in data)
{
chk ^= (byte)ch;
或者您可以使用Encoding.GetEncoding("iso-8859-1")
映射值0x00-0xFF
来解码值0x0000-0x00FF
。
注意Pete Kirkham
,除非您有一些data
字符&gt; 0x7F
,校验和将是&lt; 0x7F的。这是因为^
运算符只返回1(1 ^ 0)或(0 ^ 1),所以你必须将某位的8位置为1,校验和的8位为1。