├── LICENSE ├── MODBUS_CRC16.c └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tiago Ventura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MODBUS_CRC16.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2019 Tiago Ventura 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define INPUT_BUFFER_LENGTH (1024) 31 | 32 | static uint16_t MODBUS_CRC16_v1( const unsigned char *buf, unsigned int len ) 33 | { 34 | uint16_t crc = 0xFFFF; 35 | char i = 0; 36 | 37 | while(len--) 38 | { 39 | crc ^= (*buf++); 40 | 41 | for(i = 0; i < 8; i++) 42 | { 43 | if( crc & 1 ) 44 | { 45 | crc >>= 1; 46 | crc ^= 0xA001; 47 | } 48 | else 49 | { 50 | crc >>= 1; 51 | } 52 | } 53 | } 54 | 55 | return crc; 56 | } 57 | 58 | 59 | static uint16_t MODBUS_CRC16_v2( const unsigned char *buf, unsigned int len ) 60 | { 61 | static const uint16_t table[2] = {0x0000, 0xA001}; 62 | uint16_t crc = 0xFFFF; 63 | char bit = 0; 64 | unsigned int xor = 0; 65 | 66 | while(len--) 67 | { 68 | crc ^= (*buf++); 69 | 70 | for( bit = 0; bit < 8; bit++ ) 71 | { 72 | xor = crc & 1; 73 | crc >>= 1; 74 | crc ^= table[xor]; 75 | } 76 | } 77 | 78 | return crc; 79 | } 80 | 81 | 82 | static uint16_t MODBUS_CRC16_v3( const unsigned char *buf, unsigned int len ) 83 | { 84 | static const uint16_t table[256] = { 85 | 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 86 | 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 87 | 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 88 | 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 89 | 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 90 | 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 91 | 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 92 | 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 93 | 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 94 | 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 95 | 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 96 | 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 97 | 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 98 | 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 99 | 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 100 | 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 101 | 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 102 | 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 103 | 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 104 | 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 105 | 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 106 | 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 107 | 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 108 | 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 109 | 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 110 | 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 111 | 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 112 | 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 113 | 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 114 | 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 115 | 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 116 | 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 }; 117 | 118 | uint8_t xor = 0; 119 | uint16_t crc = 0xFFFF; 120 | 121 | while(len--) 122 | { 123 | xor = (*buf++) ^ crc; 124 | crc >>= 8; 125 | crc ^= table[xor]; 126 | } 127 | 128 | return crc; 129 | } 130 | 131 | static uint16_t MODBUS_CRC16_v4( const unsigned char *buf, unsigned int len ) 132 | { 133 | static const uint16_t table[16] = { 134 | 0x0000, 0xcc01, 0xd801, 0x1400, 0xf001, 0x3c00, 0x2800, 0xe401, 135 | 0xa001, 0x6c00, 0x7800, 0xb401, 0x5000, 0x9c01, 0x8801, 0x4400 }; 136 | 137 | uint16_t crc = 0xFFFF; 138 | 139 | while(len--) 140 | { 141 | crc = table[((*buf) ^ crc) & 0xF]; 142 | crc ^= (crc >> 4); 143 | 144 | crc = table[(((*buf++) >> 4) ^ crc) & 0xF]; 145 | crc ^= (crc >> 4); 146 | } 147 | 148 | return crc; 149 | } 150 | 151 | static void get_random_buffer( unsigned char *buf, unsigned int len ) 152 | { 153 | unsigned int i = 0; 154 | srand(time(NULL)); 155 | for( i = 0; i < len; i++ ) 156 | buf[i] = rand() % 256; 157 | } 158 | 159 | 160 | int main( int argc, char * argv[] ) 161 | { 162 | unsigned long i = 0; 163 | unsigned long n = 0; 164 | unsigned char buf[INPUT_BUFFER_LENGTH] = {0}; 165 | uint16_t (*fncrc)( const unsigned char*, unsigned int ); 166 | 167 | if( argc != 3 ) 168 | { 169 | fprintf(stderr,"Syntax: %s \n", argv[0] ); 170 | return EXIT_FAILURE; 171 | } 172 | 173 | switch( atoi(argv[1]) ) 174 | { 175 | case 1: fncrc = MODBUS_CRC16_v1; break; 176 | case 2: fncrc = MODBUS_CRC16_v2; break; 177 | case 3: fncrc = MODBUS_CRC16_v3; break; 178 | case 4: fncrc = MODBUS_CRC16_v4; break; 179 | 180 | default: 181 | fprintf(stderr,"Invalid Algorithm, (expected: 1, 2, 3 or 4)\n"); 182 | return EXIT_FAILURE; 183 | } 184 | 185 | n = atol(argv[2]); 186 | 187 | get_random_buffer( buf, INPUT_BUFFER_LENGTH ); 188 | 189 | for( i = 0; i < n; i++ ) 190 | fncrc( buf, INPUT_BUFFER_LENGTH ); 191 | 192 | return EXIT_SUCCESS; 193 | } 194 | 195 | /* end-of-file */ 196 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MODBUS CRC Calculation (Performance Test) 2 | 3 | ## CPU Model: 4 | ``` 5 | $ cat /proc/cpuinfo | grep "model name" | cut -d: -f2 6 | Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 7 | Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 8 | Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 9 | Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 10 | ``` 11 | 12 | ## Compiling: 13 | ``` 14 | $ gcc -O2 -Wall -Wextra -ansi -pedantic MODBUS_CRC16.c -o MODBUS_CRC16 15 | ``` 16 | 17 | ## Algorithm 1: 18 | ```c 19 | static uint16_t MODBUS_CRC16_v1( const unsigned char *buf, unsigned int len ) 20 | { 21 | uint16_t crc = 0xFFFF; 22 | unsigned int i = 0; 23 | char bit = 0; 24 | 25 | for( i = 0; i < len; i++ ) 26 | { 27 | crc ^= buf[i]; 28 | 29 | for( bit = 0; bit < 8; bit++ ) 30 | { 31 | if( crc & 0x0001 ) 32 | { 33 | crc >>= 1; 34 | crc ^= 0xA001; 35 | } 36 | else 37 | { 38 | crc >>= 1; 39 | } 40 | } 41 | } 42 | 43 | return crc; 44 | } 45 | ``` 46 | 47 | ### Measuring Algorithm 1 Execution Time: 48 | ``` 49 | $ time ./MODBUS_CRC16 1 1000000 50 | real 0m22.606s 51 | user 0m22.598s 52 | sys 0m0.005s 53 | ``` 54 | 55 | ## Algorithm 2 56 | ```c 57 | static uint16_t MODBUS_CRC16_v2( const unsigned char *buf, unsigned int len ) 58 | { 59 | static const uint16_t table[2] = { 0x0000, 0xA001 }; 60 | uint16_t crc = 0xFFFF; 61 | unsigned int i = 0; 62 | char bit = 0; 63 | unsigned int xor = 0; 64 | 65 | for( i = 0; i < len; i++ ) 66 | { 67 | crc ^= buf[i]; 68 | 69 | for( bit = 0; bit < 8; bit++ ) 70 | { 71 | xor = crc & 0x01; 72 | crc >>= 1; 73 | crc ^= table[xor]; 74 | } 75 | } 76 | 77 | return crc; 78 | } 79 | ``` 80 | 81 | ### Measuring Algorithm 2 Execution Time: 82 | ``` 83 | $ time ./MODBUS_CRC16 2 1000000 84 | real 0m17.392s 85 | user 0m17.389s 86 | sys 0m0.004s 87 | ``` 88 | 89 | ## Algorithm 3 90 | ```c 91 | static uint16_t MODBUS_CRC16_v3( const unsigned char *buf, unsigned int len ) 92 | { 93 | static const uint16_t table[256] = { 94 | 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 95 | 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 96 | 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 97 | 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 98 | 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 99 | 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 100 | 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 101 | 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 102 | 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 103 | 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 104 | 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 105 | 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 106 | 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 107 | 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 108 | 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 109 | 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 110 | 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 111 | 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 112 | 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 113 | 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 114 | 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 115 | 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 116 | 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 117 | 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 118 | 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 119 | 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 120 | 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 121 | 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 122 | 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 123 | 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 124 | 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 125 | 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 }; 126 | 127 | uint8_t xor = 0; 128 | uint16_t crc = 0xFFFF; 129 | 130 | while( len-- ) 131 | { 132 | xor = (*buf++) ^ crc; 133 | crc >>= 8; 134 | crc ^= table[xor]; 135 | } 136 | 137 | return crc; 138 | } 139 | ``` 140 | 141 | ### Measuring Algorithm 3 Execution Time: 142 | ``` 143 | $ time ./MODBUS_CRC16 3 1000000 144 | real 0m2.443s 145 | user 0m2.441s 146 | sys 0m0.002s 147 | ``` 148 | 149 | ### License 150 | ``` 151 | MIT License 152 | 153 | Copyright (c) 2019 Tiago Ventura 154 | 155 | Permission is hereby granted, free of charge, to any person obtaining a copy 156 | of this software and associated documentation files (the "Software"), to deal 157 | in the Software without restriction, including without limitation the rights 158 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 159 | copies of the Software, and to permit persons to whom the Software is 160 | furnished to do so, subject to the following conditions: 161 | 162 | The above copyright notice and this permission notice shall be included in all 163 | copies or substantial portions of the Software. 164 | 165 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 168 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 169 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 170 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 171 | SOFTWARE. 172 | ``` 173 | --------------------------------------------------------------------------------