CRC-16 procedure or xop?

Hi there,

I am writing a procedure to communicate with an Eurotherm temperature controller (3204), via RS232 using VDT2.xop. The controller uses the MODBUS-RTU protocol. Under this protocol, each frame of command requires a 16 bit CRC (cyclic redundancy code) check for error detection. There is a in-built function in Igor, WaveCRC (or StrCRC), that can generate a 32 bit CRC code instead of 16 bit.

It seems not possible to implement the CRC algorithm in Igor programming. Has anyone created an XOP for getting CRC-16 codes? Aslo, I guess someone has already realized MODBUS-RTU communication with Igor. It would be much appreciated if some example codes can be shared.

Cheers, Cheney
G'day Cheney,

It seems not possible to implement the CRC algorithm in Igor programming.


I very much doubt that. Igor's programming capabilities are quite broad. The bit manipulation capabilities can be somewhat cumbersome, but they exist. As a starting point, at least, check out the Wikipedia article: http://en.wikipedia.org/wiki/Cyclic_redundancy_check

The polynomial is given for "CRC-16-IBM x^16 + x^15 + x^2 + 1 (Bisync, Modbus, USB, ANSI X3.28, many others; also known as CRC-16 and CRC-16-ANSI)". Along with the prescription in the article for calculating a CRC, and a lot of work, I think it ought to be possible to code an Igor CRC-16 function.
more info: This is one of the simpler CRC-16 code versions I found on the net
http://code.google.com/p/libext2fs-wii/source/browse/trunk/source/crc16…

The polynomial used appears to be the one you want for the MODBUS protocol. The choice you have is to convert this to an XOP, or translate the C code into Igor. A handy hex-to-dec conversion you can use in Igor is sscanf HexString,"%i", DecVariable, where DecVariable becomes the converted numeric value of the hexadecimal string (starting with prefix 0x).
edit: this isn't correct, but I just copied the code!
edit2: now correct (forgot that ^ is bitwiseXOR in C), but it's not the modbus one.
Function crc16ibm(crc, buf)
    variable crc
    string buf

    variable ii, buflen

    buflen = strlen(buf)

    make/free/n=256/u/w LUT
    LUT[0,7]={      0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241}
    LUT[8,15]={    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440}
    LUT[16,23]={        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40}
    LUT[24,31]={        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841}
    LUT[32,39]={        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40}
    LUT[40,47]={        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41}
    LUT[48,55]={         0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641}
    LUT[56,63]={         0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040}
    LUT[64,71]={         0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240}
    LUT[72,79]={         0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441}
    LUT[80,87]={         0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41}
    LUT[88,95]={         0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840}
    LUT[96,103]={         0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41}
    LUT[104,111]={         0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40}
    LUT[112,119]={         0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640}
    LUT[120,127]={         0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041}
    LUT[128,135]={         0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240}
    LUT[136,143]={         0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441}
    LUT[144,151]={         0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41}
    LUT[152,159]={         0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840}
    LUT[160,167]={         0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41}
    LUT[168,175]={         0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40}
    LUT[176,183]={         0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640}
    LUT[184,191]={         0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041}
    LUT[192,199]={         0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241}
    LUT[200,207]={         0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440}
    LUT[208,215]={         0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40}
    LUT[216,223]={         0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841}
    LUT[224,231]={         0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40}
    LUT[232,239]={         0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41}
    LUT[240,247]={         0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641}
    LUT[248,255]={         0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040}

    for(ii = 0; ii < buflen ; ii += 1)
        crc = (((crc / 256 ) & 0xff) %^  LUT[(crc %^ char2num(buf[ii])) & 0xff]) & 0x0000ffff;
    endfor
    return crc
end
And this is the modbus crc version.
Function crc16modbus(buf)
    string buf
 
    variable ii, buflen
    buflen = strlen(buf)
 
    make/free/n=256/u/w LUT
    make/n=1/u/w/free crctemp = 0
    make/n=1/w/U/free ntemp = 0
    LUT[0,7]={      0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241}
    LUT[8,15]={    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440}
    LUT[16,23]={        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40}
    LUT[24,31]={        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841}
    LUT[32,39]={        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40}
    LUT[40,47]={        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41}
    LUT[48,55]={         0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641}
    LUT[56,63]={         0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040}
    LUT[64,71]={         0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240}
    LUT[72,79]={         0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441}
    LUT[80,87]={         0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41}
    LUT[88,95]={         0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840}
    LUT[96,103]={         0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41}
    LUT[104,111]={         0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40}
    LUT[112,119]={         0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640}
    LUT[120,127]={         0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041}
    LUT[128,135]={         0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240}
    LUT[136,143]={         0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441}
    LUT[144,151]={         0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41}
    LUT[152,159]={         0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840}
    LUT[160,167]={         0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41}
    LUT[168,175]={         0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40}
    LUT[176,183]={         0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640}
    LUT[184,191]={         0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041}
    LUT[192,199]={         0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241}
    LUT[200,207]={         0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440}
    LUT[208,215]={         0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40}
    LUT[216,223]={         0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841}
    LUT[224,231]={         0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40}
    LUT[232,239]={         0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41}
    LUT[240,247]={         0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641}
    LUT[248,255]={         0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040}
   
    crctemp[0] = 0xFFFF
   
    for(ii = 0; ii < buflen ; ii += 1)
        ntemp[0] = crctemp[0] %^ char2num(buf[ii])
        crctemp[0] = (crctemp[0]/256) %^ LUT[ntemp[0] & 0x00FF]
    endfor
    return crctemp[0]
end
Thanks a lot. This is my first post on the forum and it surpises me to get replies so quickly.

Actually I also searched similar topics in Igor Mailing List. From there I have found similar prodecures written by Tony Withers (http://talc.geo.umn.edu/people/researchers/withe012/software.htm). His prodecure includes a delicate function for CRC16, as attached below. I was not sure how to do bitwise operation on a wave.
(2).txt (535 bytes)