github.com/simpleiot/simpleiot@v0.18.3/modbus/crc.go (about) 1 package modbus 2 3 import ( 4 "encoding/binary" 5 "errors" 6 ) 7 8 // RtuCrc calculates CRC for a Modbus RTU packet 9 func RtuCrc(buf []byte) uint16 { 10 crc := uint16(0xFFFF) 11 12 for _, b := range buf { 13 crc ^= uint16(b) // XOR byte into least sig. byte of crc 14 15 for i := 8; i != 0; i-- { // Loop over each bit 16 if (crc & 0x0001) != 0 { // If the LSB is set 17 crc >>= 1 // Shift right and XOR 0xA001 18 crc ^= 0xA001 19 } else { // Else LSB is not set 20 crc >>= 1 // Just shift right 21 } 22 } 23 } 24 // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) 25 return (crc >> 8) | (crc << 8) 26 } 27 28 // ErrCRC is returned if a crc check fails 29 var ErrCRC = errors.New("CRC error") 30 31 // ErrNotEnoughData is returned if not enough data 32 var ErrNotEnoughData = errors.New("Not enough data to calculate CRC") 33 34 // CheckRtuCrc returns error if CRC fails 35 func CheckRtuCrc(packet []byte) error { 36 if len(packet) < 4 { 37 return ErrNotEnoughData 38 } 39 40 crcCalc := RtuCrc(packet[:len(packet)-2]) 41 42 crcPacket := binary.BigEndian.Uint16(packet[len(packet)-2:]) 43 if crcCalc != crcPacket { 44 return ErrCRC 45 } 46 47 return nil 48 }