简体   繁体   中英

C# code converted from C++ not working

Consider the following C++ code which sends data over RS232 to a device.

  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;

}

I've rewritten this code in C# as the following:

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

And the string is converted to byte array before sending

bytes = data.Select(c=>(byte)c).ToArray(); Now the question is that the C# code never get a response from the device on these requests. It does send other data back so baudrate and all that is correct.

I have some doubts about the translation of the buffer from the C++ code. 0x020x01C data 0x03 checksum \\r\\n

became

\\x02\\x01C data \\x03 checksum \\r\\n

Or else would the rewrite of the checksum calculation be correct? First calculation of checksum of the bytes and then converted back to char

This was an odd one. As always, I created a unit test. Then I built the C++ version using C++ CLR and got the test to compare output with your input "SRT1". Initially, it failed with

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

That 1C looks rather familiar...

The error seems to be in the assumption that the string "\\x02\\x01C" + data ; is the same as "\\x02" + "\\x01" + "C" + data; whereas the hex escape in will continue to be interpreting digits until it finds a character which is not a hex digit. So the 'C' becomes part of the hex escape.

Breaking up the literal allows the parser to parse the 'C' as a separate character, the unit test then passes.

Mmmh... Your problem is perhaps that some code uses Encoding.ASCII.GetBytes(finalString) to finally convert the string to byte[] , but the checksum could be >= 0x7F, so a non-ASCII character. Convert the string to byte[] manually after Generate like:

string result = Generate();
byte[] bytes = new byte[result.Length];
for (int i = 0; i < result.Length; i++)
{
    bytes[i] = (byte)result[i];
}

and just to be sure change:

foreach (byte b in Encoding.ASCII.GetBytes(data))
{
    chk ^= b;

to

foreach (char ch in data)
{
    chk ^= (byte)ch;

Or you can use the Encoding.GetEncoding("iso-8859-1") that maps values 0x00-0xFF to unicode values 0x0000-0x00FF .

as Pete Kirkham noted, unless you have some data with chars > 0x7F , the checksum will be < 0x7F. This because the ^ operator will return 1 only with (1 ^ 0) or (0 ^ 1), so you must have the eight bit at 1 somewhere to have a checksum with the eight bit at 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM