2

I have string: 02 03 04 50 00 01. I need to calculate the CRC for this string.

I have a function that counts a CRC:

public static UInt16 ModRTU_CRC(ushort[] buf, int len)
        {
            UInt16 crc = 0xFFFF;

            for (int pos = 0; pos < len; pos++)
            {
                crc ^= (UInt16)buf[pos];

                for (int i = 8; i != 0; i--)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                        crc >>= 1;
                }
            }
            return crc;
        }

I want to cast a string to an array of ushort:

ushort[] result = cmd.Split(' ').Select(item => Convert.ToUInt16(item, 16)).ToArray();

but such an array is returned to me: 2 3 4 80 0 1.

Please tell me what should I do in order to correctly calculate the CRC.

Falco Alexander
  • 3,092
  • 2
  • 20
  • 39
  • Is `50` witni the input string a *hexadecimal* (`0x50 == 80`) or *decimal* (`50`) value? If it's decimal, then `Convert.ToUInt16(item, 10)` (note `10` instead of `16`) – Dmitry Bychenko Mar 11 '20 at 13:37
  • @DmitryBychenko My string in hexadecimal – Aleksey Malashenkov Mar 11 '20 at 13:41
  • then, your code is correct: note, that `0x50 == 80` so you have `{2, 3, 4, 80, 0, 1}` array. Back to string (hexadecimal representation) `80.ToString("x2") == "50"` – Dmitry Bychenko Mar 11 '20 at 13:42
  • @DmitryBychenko Yes Dmitry, I used your function from your other answer =) But there is one problem. I forgot to say about it ... A line is a Modbus command so the numbers in it: 02 03 0450 0001 – Aleksey Malashenkov Mar 11 '20 at 13:46
  • @DmitryBychenko Or do I need to use exactly what is obtained in your function to calculate the CRC? – Aleksey Malashenkov Mar 11 '20 at 13:48
  • I usually use the Sunshine webpage to help get CRC working. There is a calculator on the line below and full sample code on other pages. First verify the options on the calculator before trying the c# code : http://www.sunshine2k.de/coding/javascript/crc/crc_js.html – jdweng Mar 11 '20 at 13:50

1 Answers1

4

It seems, you want to combine two bytes into ushort, i.e. for given

  string cmd = "02 03 04 50 00 01";

you want to get

  {0x0203, 0x0405, 0x0001}

If it's you case,

  using System.Linq;

  ...

  string cmd = "02 03 04 50 00 01";

  ushort[] result = cmd
    .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
    .Select((value, index) => new { index, value = Convert.ToInt32(value, 16) })
    .GroupBy(item => item.index / 2, item => item.value)
    .Select(group => (UInt16)(group.Aggregate((s, a) => s * 256 + a)))
    .ToArray();

Let's have a look:

  Console.WriteLine(string.Join(" ", data.Select(item => item.ToString("x4"))));

Outcome:

  0203 0450 0001

Edit: If you want not to combine first skip items (see comments below), you can try modifying GroupBy:

  int skip = 2;

  ushort[] data = source
    .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
    .Select((value, index) => new { index, value = Convert.ToInt32(value, 16) })
    .GroupBy(item => item.index >= skip ? item.index / 2 : -item.index - 1, 
             item => item.value)
    .Select(group => (UInt16)(group.Aggregate((s, a) => s * 256 + a)))
    .ToArray();

  Console.WriteLine(string.Join(" ", data.Select(item => item.ToString("x4"))));

Outcome: (02 and 03 left intact, 04 combined with 50, 00 with 01)

  0002 0003 0450 0001
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215