ModBus CRC calculation

I’m trying to calculate the CRC for sent and received ModBus communication. I’ve tried using Christian Schmitz 's CRC code posted several weeks ago, https://forum.xojo.com/25931-crc16-function , but the results are not correct. Here’s what I got from WattNode for this calculation using C:

// Compute the MODBUS RTU CRC
UInt16 ModRTU_CRC(byte[] buf, int len)
{
UInt16 crc = 0xFFFF;

for (int pos = 0; pos < len; pos++) {
crc ^= (UInt16)buf[pos]; // XOR byte into least sig. byte of crc

for (int i = 8; i != 0; i--) {    // Loop over each bit
  if ((crc & 0x0001) != 0) {      // If the LSB is set
    crc >>= 1;                    // Shift right and XOR 0xA001
    crc ^= 0xA001;
  }
  else                            // Else LSB is not set
    crc >>= 1;                    // Just shift right
}

}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
return crc;
}

I don’t know C so a lot of this is meaningless to me, and I have no idea how to rewrite it for Xojo. Any help will be greatly appreciated!

There are a couple of ModBus VB6 projects over at Planet Source Code that might help you out: http://planet-source-code.com/vb/scripts/BrowseCategoryOrSearchResults.asp?txtCriteria=modbus&lngWId=1

You could try this one (I wrote it some years ago and used to work)

function crc16ModBus (m as MemoryBlock) as UInt16
  Static wCRCTable() as UInt16
  if wCRCTable.Ubound=-1 then
    dim wCRCTable_() as UInt16=array(&h0000, &hC0C1, &hC181, &h0140, &hC301, &h03C0, &h0280, &hC241, _
    &hC601, &h06C0, &h0780, &hC741, &h0500, &hC5C1, &hC481, &h0440, _
    &hCC01, &h0CC0, &h0D80, &hCD41, &h0F00, &hCFC1, &hCE81, &h0E40, _
    &h0A00, &hCAC1, &hCB81, &h0B40, &hC901, &h09C0, &h0880, &hC841, _
    &hD801, &h18C0, &h1980, &hD941, &h1B00, &hDBC1, &hDA81, &h1A40, _
    &h1E00, &hDEC1, &hDF81, &h1F40, &hDD01, &h1DC0, &h1C80, &hDC41, _
    &h1400, &hD4C1, &hD581, &h1540, &hD701, &h17C0, &h1680, &hD641, _
    &hD201, &h12C0, &h1380, &hD341, &h1100, &hD1C1, &hD081, &h1040, _
    &hF001, &h30C0, &h3180, &hF141, &h3300, &hF3C1, &hF281, &h3240, _
    &h3600, &hF6C1, &hF781, &h3740, &hF501, &h35C0, &h3480, &hF441, _
    &h3C00, &hFCC1, &hFD81, &h3D40, &hFF01, &h3FC0, &h3E80, &hFE41, _
    &hFA01, &h3AC0, &h3B80, &hFB41, &h3900, &hF9C1, &hF881, &h3840, _
    &h2800, &hE8C1, &hE981, &h2940, &hEB01, &h2BC0, &h2A80, &hEA41, _
    &hEE01, &h2EC0, &h2F80, &hEF41, &h2D00, &hEDC1, &hEC81, &h2C40, _
    &hE401, &h24C0, &h2580, &hE541, &h2700, &hE7C1, &hE681, &h2640, _
    &h2200, &hE2C1, &hE381, &h2340, &hE101, &h21C0, &h2080, &hE041, _
    &hA001, &h60C0, &h6180, &hA141, &h6300, &hA3C1, &hA281, &h6240, _
    &h6600, &hA6C1, &hA781, &h6740, &hA501, &h65C0, &h6480, &hA441, _
    &h6C00, &hACC1, &hAD81, &h6D40, &hAF01, &h6FC0, &h6E80, &hAE41, _
    &hAA01, &h6AC0, &h6B80, &hAB41, &h6900, &hA9C1, &hA881, &h6840, _
    &h7800, &hB8C1, &hB981, &h7940, &hBB01, &h7BC0, &h7A80, &hBA41, _
    &hBE01, &h7EC0, &h7F80, &hBF41, &h7D00, &hBDC1, &hBC81, &h7C40, _
    &hB401, &h74C0, &h7580, &hB541, &h7700, &hB7C1, &hB681, &h7640, _
    &h7200, &hB2C1, &hB381, &h7340, &hB101, &h71C0, &h7080, &hB041, _
    &h5000, &h90C1, &h9181, &h5140, &h9301, &h53C0, &h5280, &h9241, _
    &h9601, &h56C0, &h5780, &h9741, &h5500, &h95C1, &h9481, &h5440, _
    &h9C01, &h5CC0, &h5D80, &h9D41, &h5F00, &h9FC1, &h9E81, &h5E40, _
    &h5A00, &h9AC1, &h9B81, &h5B40, &h9901, &h59C0, &h5880, &h9841, _
    &h8801, &h48C0, &h4980, &h8941, &h4B00, &h8BC1, &h8A81, &h4A40, _
    &h4E00, &h8EC1, &h8F81, &h4F40, &h8D01, &h4DC0, &h4C80, &h8C41, _
    &h4400, &h84C1, &h8581, &h4540, &h8701, &h47C0, &h4680, &h8641, _
    &h8201, &h42C0, &h4380, &h8341, &h4100, &h81C1, &h8081, &h4040 _
    )
    for i as integer=0 to wCRCTable_.ubound
      wCRCTable.Append wCRCTable_(i)
    next
  end if
  
  dim nTemp as Byte
  dim wCRCWord as UInt16=&hFFFF
  dim wLength as UInt16=m.Size-1
  for i as integer=0 to wLength
    nTemp=BitwiseXor(m.Byte(i),wCRCWord)
    wCRCWord=ShiftRight(wCRCWord,8)
    wCRCWord=BitwiseXor(wCRCWord,wCRCTable(nTemp))
  next
  
  dim CrcByteLow as UInt16
  dim CrcByteHigh as Uint16
  
  CrcByteLow = ShiftRight(wCRCWord,8)
  CrcByteHigh = ShiftLeft(wCRCWord,8)
  
  wCRCword = Bitwise.BitOr(CrcByteHigh,CrcByteLow)
  
  Return wCRCWord
end function
1 Like

Thanks Antonio–I appreciate your quick response and your sharing the code you wrote. Unfortunately, I’m too much of a novice to know what to do with the function. If I paste it into my code, or paste it into a Method, I get a syntax error at “end function”. I’ve tried various other ways of using your code and I’m not making any progress. Can you instruct me on how to use this function?

Thanks

Because the first line ‘function’ and the last line ‘end function’ is added, you can copy the whole method using paste from the top menu.

If you want to copy the code inside an existing method you made, leave the first and last line out.
Then add ‘m as MemoryBlock’ as parameter and ‘UInt16’ as return value on the right.

Example application:

ComCheck Modbus Edition :slight_smile:

Modbus tcp:

Xojo Modbus Example

Please look inside notes in source code for credits

Interesting, but a single class with more OOP approach would be better…
Somewhere I should have it, when I find it (it was almost completed) I will post so who is interested can use or complete it

@Antonio Rinaldi : Do you have an example MODBUS TCP class somewhere?

@Jaap Cammeraat did you try my examples above ?

Yes @Antonio Rinaldi OOP and a single class is the way to go…

Working code with CRC calculation (that i see you have asked about elsewhere)
TCP and RTU Modbus Code

I use a tool called “Ananas” to simulate a server and debug messages.

Could you give me a list of the variables you are trying to get from the plc ?
Maybe I could help you a bit further width this information.

[quote=232497:@Antonio Rinaldi]Interesting, but a single class with more OOP approach would be better…
Somewhere I should have it, when I find it (it was almost completed) I will post so who is interested can use or complete it[/quote]
Just in case - I’ve recently created an example. You’ll find it in this related Forum Post.