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

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 ?