0

I am very new to Ruby, please help.

This is a C code which I need to convert into Ruby.

Passing values [1,2,3,4,5] it gives me B059 in HEX

    unsigned short CalcCrc16(const unsigned char *Data,unsigned short DataLen)
    {
      unsigned short Temp;
      unsigned short Crc;
      Crc = 0;
      while (DataLen--)
      {
             Temp = (unsigned short)((*Data++) ^ (Crc >> 8));
             Temp ^= (Temp >> 4);
             Temp ^= (Temp >> 2);
             Temp ^= (Temp >> 1);
             Crc = (Crc << 8) ^ (Temp << 15) ^ (Temp << 2) ^ Temp;
      }
        return Crc; 
   }

This is the Ruby code I have tried:

class CRC16 
  def CRC16.CalculateCrc16(data) 
    crc = 0x0000 
    temp = 0x0000 
    i = 0 
    while i < data.Length 
      value = data[i] 
      temp = (value ^ (crc >> 8)) 
      temp = (temp ^ (temp >> 4)) 
      temp = (temp ^ (temp >> 2)) 
      temp = (temp ^ (temp >> 1)) 
      crc = (((crc << 8) ^ (temp << 15) ^ (temp << 2) ^ temp)) 
      i += 1 
    end 
    return crc 
  end 
end

Please help me to convert this code into Ruby. Thanks Deepak

James Dunn
  • 8,064
  • 13
  • 53
  • 87
Deepak Kumar Jha
  • 462
  • 6
  • 15
  • 3
    What have you tried? Nobody will just do the work for you if you don't show at least what you've tried or where your specific problem is. – Patrick Oscity Aug 20 '13 at 11:19

1 Answers1

4

You are almost there.

Here is the fix:

class CRC16 
  def CRC16.CalculateCrc16(data) 
    crc = 0
    temp = 0
    i = 0 
    while i < data.length    # Modified from OP version
      value = data[i] 
      temp = (value ^ (crc >> 8)) 
      temp = (temp ^ (temp >> 4)) 
      temp = (temp ^ (temp >> 2)) 
      temp = (temp ^ (temp >> 1)) 
      crc = (((crc << 8) ^ (temp << 15) ^ (temp << 2) ^ temp))
      crc &= 0xffff          # New - keep integer in "unsigned short" bit space
      i += 1 
    end 
    return crc 
  end 
end

I changed just two things to make it work as per the C version:

  • Length -> length, a typo
  • Ruby doesn't do short, or any other kind of restriction on integer size. You have to add it. That is what crc &= 0xffff is doing. Without it, bits shifted "out" of the short come back to haunt you and give a nonsense result.

In addition, I replaced 0x0000 with 0, as it looked like an attempt to get Ruby to treat the integers as "short", which is not possible this way.

Neil Slater
  • 26,512
  • 6
  • 76
  • 94
  • 1
    `crc &= 0xffff` makes sense to add in the C version to deal with variant `short` sizes. (uint32_t be better.) – chux - Reinstate Monica Aug 20 '13 at 12:07
  • thank you very much...i got my answer from your solution...:) – Deepak Kumar Jha Aug 20 '13 at 12:13
  • one more query if i want to pass '12345' in place of [1,2,3,4,5]. To get the same o/p . can you please help me where to change in the code to get the desired result b059. – Deepak Kumar Jha Aug 20 '13 at 12:32
  • @Deepak Kumar Jha: The character `"1"` is different to the number `1`, are you sure you want this? Does your input really consist of an array of values 0 to 9? If so, a Ruby one-liner would be `"12345".chars.map { |c| c.to_i }` or more generally `numbers = str.chars.map { |c| c.to_i }` where `str` is your input string. – Neil Slater Aug 20 '13 at 13:06