File view
| 1 | /* MODBUS_master.c Copyright January 2006, RabbitSemiconductor |
| 2 | |
| 3 | Modifications: |
| 4 | JLC June 2006 added MODBUS_CRC |
| 5 | |
| 6 | This library supports the following MODBUS commands: |
| 7 | |
| 8 | 0x01 Read Coils |
| 9 | 0x03 Read Holding Registers |
| 10 | 0x05 Write Single Coil |
| 11 | 0x06 Write Single Register |
| 12 | 0x0F Write multiple Coils |
| 13 | |
| 14 | It is independant of the communications method in use. It is equally |
| 15 | compatible with TCP and serial interfaces. Its primary function is to |
| 16 | develop the MODBUS APU. It requires the following functions from the |
| 17 | appropriate interface library/program: |
| 18 | MBM_Send_ADU ( *ADUaddress, ADUlength ) |
| 19 | This function must send the ADU to the defined slave device and return |
| 20 | an appropriate success/failure status value. It must also insert |
| 21 | the response ADU from the slave into the same ADU buffer. |
| 22 | */ |
| 23 | |
| 24 | /*** BeginHeader */ |
| 25 | #ifndef __MBMASTER |
| 26 | #define __MBMASTER |
| 27 | |
| 28 | #define MB_SUCCESS 0 |
| 29 | #define MB_BADFUNC 0x01 // Illegal Function |
| 30 | #define MB_BADADDR 0x02 // Illegal Data Address |
| 31 | #define MB_BADDATA 0x03 // Illegal Data Value |
| 32 | #define MB_SLAVEFAILURE 0x04 // Slave Device Failure |
| 33 | #define MB_BUSY 0x06 // Target is busy with another request |
| 34 | #define MB_NORESP 0x0B // No response from target |
| 35 | #define MB_DEVNOTSET 0x10 // device not properly set up |
| 36 | |
| 37 | #define MBM_INVALID_PARAMETER -1 |
| 38 | #define MBM_PACKET_ERROR -2 |
| 39 | #define MBM_BAD_ADDRESS -3 |
| 40 | #define MBM_BAD_BYTECOUNT -4 |
| 41 | #define MB_CRC_ERROR -5 |
| 42 | |
| 43 | // Rx message offsets |
| 44 | #define ADU_OFF_ADDRESS 0 |
| 45 | #define ADU_OFF_FUNCTION 1 |
| 46 | #define ADU_OFF_EXCEPTION 2 |
| 47 | #define ADU_OFF_BYTECOUNT 2 |
| 48 | |
| 49 | #ifndef MODBUS_DEBUG |
| 50 | #define MODBUS_DEBUG nodebug |
| 51 | #endif |
| 52 | /*** EndHeader */ |
| 53 | |
| 54 | |
| 55 | /*** BeginHeader _initADU, _insertWord */ |
| 56 | |
| 57 | void _initADU ( int MB_address, int FunctionCode, int PDUbyteCount ); |
| 58 | void _insertWord ( int Value ); |
| 59 | void _insertByte ( int Value ); |
| 60 | int _getADUword ( int Offset ); |
| 61 | |
| 62 | extern char mbADU[255]; // MODBUS packet |
| 63 | extern char *pmbADU; //pointer to mbPacket |
| 64 | |
| 65 | /*** EndHeader */ |
| 66 | |
| 67 | char mbADU[255]; // MODBUS packet |
| 68 | char *pmbADU; //pointer to mbPacket |
| 69 | |
| 70 | /* START FUNCTION DESCRIPTION ******************************************** |
| 71 | _initADU <Modbus_Master.LIB> |
| 72 | |
| 73 | SYNTAX: _initADU ( int MB_address, int FunctionCode, int PDUbyteCount ) |
| 74 | |
| 75 | DESCRIPTION: Initialize the MODBUS ADU |
| 76 | |
| 77 | PARAMETER1: Modbus target address |
| 78 | |
| 79 | PARAMETER2: Modbus function |
| 80 | |
| 81 | PARAMETER3: nbr of data bytes in the PDU |
| 82 | |
| 83 | RETURN VALUE: none |
| 84 | |
| 85 | The format of a MODBUS Protocol Data Unit (PDU) is: Function Code + Data |
| 86 | |
| 87 | END DESCRIPTION **********************************************************/ |
| 88 | |
| 89 | MODBUS_DEBUG |
| 90 | void _initADU ( int MB_address, int FunctionCode, int PDUbyteCount ) |
| 91 | { |
| 92 | pmbADU = mbADU; // init pointer |
| 93 | //_initMBMpacket ( PDUbyteCount+1 ); // include Function code byte |
| 94 | *pmbADU++ = MB_address; // insert target address |
| 95 | *pmbADU++ = FunctionCode; // and Function Code |
| 96 | return; |
| 97 | } |
| 98 | |
| 99 | |
| 100 | // insert a word - MSByte first - into the transmit ADU |
| 101 | MODBUS_DEBUG |
| 102 | void _insertWord ( int Value ) |
| 103 | { *pmbADU++ = Value >> 8; // insert high byte |
| 104 | *pmbADU++ = Value; // and low byte |
| 105 | return; |
| 106 | } |
| 107 | |
| 108 | // insert a byte into the transmit ADU |
| 109 | MODBUS_DEBUG |
| 110 | void _insertByte ( int Value ) |
| 111 | { *pmbADU++ = Value; |
| 112 | return; |
| 113 | } |
| 114 | |
| 115 | // retrieve a word - MSByte first - from the received ADU |
| 116 | MODBUS_DEBUG |
| 117 | int _getADUword ( int Offset ) |
| 118 | { auto ADUword; |
| 119 | ADUword = mbADU[Offset]<<8; // get MSByte |
| 120 | ADUword |= mbADU[Offset+1]; // and LSByte |
| 121 | return ADUword; |
| 122 | } |
| 123 | |
| 124 | /* START FUNCTION DESCRIPTION ******************************************** |
| 125 | MBM_ReadCoils 0x01 |
| 126 | |
| 127 | SYNTAX: int MBM_ReadCoils ( int MB_address, int* Result, |
| 128 | int Starting_Coil, int Nbr_of-Coils ); |
| 129 | |
| 130 | DESCRIPTION: Read the state of the specified coils. The function will |
| 131 | create the MODBUS ADU, in mbADU, with the target address |
| 132 | pre-pended. |
| 133 | |
| 134 | PARAMETER1: MODBUS addresss of the target device |
| 135 | |
| 136 | PARAMETER2: Address to put the result |
| 137 | The state of the coils: 1 = on, 0 = off |
| 138 | Each coil state will occupy one bit of the result with |
| 139 | the first coil in bit 0, the next in bit 1, etc |
| 140 | |
| 141 | PARAMETER3: Starting coil number, 1 relative, to read |
| 142 | |
| 143 | PARAMETER4: Number of coils to read - max of 16 |
| 144 | |
| 145 | RETURN VALUE: MB_SUCCESS |
| 146 | MBM_INVALID_PARAMETER |
| 147 | MBM_PACKET_ERROR |
| 148 | MBM_BAD_ADDRESS |
| 149 | |
| 150 | END DESCRIPTION **********************************************************/ |
| 151 | |
| 152 | /*** BeginHeader MBM_ReadCoils */ |
| 153 | int MBM_ReadCoils ( int MB_address, int* Result, int Starting_Coil, |
| 154 | int Nbr_of_Coils ); |
| 155 | /*** EndHeader */ |
| 156 | |
| 157 | MODBUS_DEBUG |
| 158 | int MBM_ReadCoils ( int MB_address, int* Result, int Starting_Coil, |
| 159 | int Nbr_of_Coils ) |
| 160 | { |
| 161 | auto int ADUStatus; |
| 162 | auto int CoilStatus; |
| 163 | |
| 164 | if ( Starting_Coil < 0 ) return MBM_INVALID_PARAMETER; |
| 165 | if ( Nbr_of_Coils > 16 || Nbr_of_Coils < 0 ) return MBM_INVALID_PARAMETER; |
| 166 | |
| 167 | _initADU( MB_address, 0x01, 4 ); |
| 168 | _insertWord ( Starting_Coil ); |
| 169 | _insertWord ( Nbr_of_Coils ); |
| 170 | |
| 171 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 172 | |
| 173 | if ( ADUStatus != MB_SUCCESS ) return ADUStatus; |
| 174 | if ( mbADU[ADU_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 175 | if ( mbADU[ADU_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 176 | if ( mbADU[ADU_OFF_BYTECOUNT] > 2 ) return MBM_BAD_BYTECOUNT; |
| 177 | |
| 178 | if ( Nbr_of_Coils > 8 ) CoilStatus = _getADUword (3); |
| 179 | else CoilStatus = (int)mbADU[3] & 0xFF; |
| 180 | |
| 181 | *Result = CoilStatus; |
| 182 | return MB_SUCCESS; |
| 183 | } // MBM_ReadCoils |
| 184 | |
| 185 | |
| 186 | /* START FUNCTION DESCRIPTION ******************************************** |
| 187 | MBM_ReadRegs 0x03 |
| 188 | |
| 189 | SYNTAX: int MBM_ReadRegs ( int MB_address, int* Result, |
| 190 | int Starting_Reg, int Nbr_of_Regs ); |
| 191 | |
| 192 | DESCRIPTION: Read the specified registers. The function will |
| 193 | create the MODBUS ADU, in mbADU, with the target address |
| 194 | pre-pended. |
| 195 | |
| 196 | PARAMETER1: MODBUS addresss of the target device |
| 197 | |
| 198 | PARAMETER2: Starting address to put the results |
| 199 | |
| 200 | PARAMETER3: Starting register number, 1 relative, to read |
| 201 | |
| 202 | PARAMETER4: Number of registers to read |
| 203 | |
| 204 | RETURN VALUE: MB_SUCCESS |
| 205 | MBM_INVALID_PARAMETER |
| 206 | MBM_PACKET_ERROR |
| 207 | MBM_BAD_ADDRESS |
| 208 | |
| 209 | END DESCRIPTION **********************************************************/ |
| 210 | |
| 211 | /*** BeginHeader MBM_ReadRegs */ |
| 212 | int MBM_ReadRegs ( int MB_address, int* Result, int Starting_Reg, |
| 213 | int Nbr_of_Regs ); |
| 214 | /*** EndHeader */ |
| 215 | |
| 216 | MODBUS_DEBUG |
| 217 | int MBM_ReadRegs ( int MB_address, int* Result, int Starting_Reg, |
| 218 | int Nbr_of_Regs ) |
| 219 | { |
| 220 | auto int ADUStatus; |
| 221 | auto int RegValue; |
| 222 | auto int Count; |
| 223 | |
| 224 | if ( Starting_Reg < 0 ) return MBM_INVALID_PARAMETER; |
| 225 | if ( Nbr_of_Regs <= 0 || Nbr_of_Regs > 125 ) return MBM_INVALID_PARAMETER; |
| 226 | |
| 227 | _initADU( MB_address, 0x03, 4 ); |
| 228 | _insertWord ( Starting_Reg ); |
| 229 | _insertWord ( Nbr_of_Regs ); |
| 230 | |
| 231 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 232 | |
| 233 | if ( ADUStatus != MB_SUCCESS ) return ADUStatus; |
| 234 | if ( mbADU[ADU_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 235 | if ( mbADU[ADU_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 236 | |
| 237 | Result+= Starting_Reg; |
| 238 | for ( Count=0; Count<Nbr_of_Regs; Count+=1 ) |
| 239 | *Result++ = _getADUword(3+(Count*2)); |
| 240 | |
| 241 | return MB_SUCCESS; |
| 242 | } // MBM_ReadRegs |
| 243 | |
| 244 | |
| 245 | /* START FUNCTION DESCRIPTION ******************************************** |
| 246 | MBM_ReadInRegs 0x04 |
| 247 | |
| 248 | SYNTAX: int MBM_ReadInRegs ( int MB_address, int* Result, |
| 249 | int Starting_Reg, int Nbr_of_Regs ); |
| 250 | |
| 251 | DESCRIPTION: Read the specified input registers. The function will |
| 252 | create the MODBUS ADU, in mbADU, with the target address |
| 253 | pre-pended. |
| 254 | |
| 255 | PARAMETER1: MODBUS addresss of the target device |
| 256 | |
| 257 | PARAMETER2: Starting address to put the results |
| 258 | |
| 259 | PARAMETER3: Starting input register number, 1 relative, to read |
| 260 | |
| 261 | PARAMETER4: Number of registers to read |
| 262 | |
| 263 | RETURN VALUE: MB_SUCCESS |
| 264 | MBM_INVALID_PARAMETER |
| 265 | MBM_PACKET_ERROR |
| 266 | MBM_BAD_ADDRESS |
| 267 | |
| 268 | END DESCRIPTION **********************************************************/ |
| 269 | |
| 270 | /*** BeginHeader MBM_ReadInRegs */ |
| 271 | int MBM_ReadInRegs ( int MB_address, int* Result, int Starting_Reg, |
| 272 | int Nbr_of_Regs ); |
| 273 | /*** EndHeader */ |
| 274 | |
| 275 | MODBUS_DEBUG |
| 276 | int MBM_ReadInRegs ( int MB_address, int* Result, int Starting_Reg, |
| 277 | int Nbr_of_Regs ) |
| 278 | { |
| 279 | auto int ADUStatus; |
| 280 | auto int RegValue; |
| 281 | auto int Count; |
| 282 | |
| 283 | if ( Starting_Reg < 0 ) return MBM_INVALID_PARAMETER; |
| 284 | if ( Nbr_of_Regs <= 0 || Nbr_of_Regs > 125 ) return MBM_INVALID_PARAMETER; |
| 285 | |
| 286 | _initADU( MB_address, 0x04, 4 ); |
| 287 | _insertWord ( Starting_Reg ); |
| 288 | _insertWord ( Nbr_of_Regs ); |
| 289 | |
| 290 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 291 | |
| 292 | if ( ADUStatus != MB_SUCCESS ) return ADUStatus; |
| 293 | if ( mbADU[ADU_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 294 | if ( mbADU[ADU_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 295 | |
| 296 | for ( Count=0; Count<Nbr_of_Regs; Count+=1 ) |
| 297 | *Result++ = _getADUword(3+(Count*2)); |
| 298 | |
| 299 | return MB_SUCCESS; |
| 300 | } // MBM_ReadInRegs |
| 301 | |
| 302 | |
| 303 | /* START FUNCTION DESCRIPTION ******************************************** |
| 304 | MBM_WriteCoil 0x05 |
| 305 | |
| 306 | SYNTAX: int MBM_WriteCoil ( int MB_address, int CoilNbr, |
| 307 | int CoilState ); |
| 308 | |
| 309 | DESCRIPTION: write a value to a single coil |
| 310 | |
| 311 | PARAMETER1: MODBUS addresss of the target device |
| 312 | |
| 313 | PARAMETER2: Coil number |
| 314 | |
| 315 | PARAMETER3: Coil state |
| 316 | |
| 317 | RETURN VALUE: MB_SUCCESS |
| 318 | MBM_INVALID_PARAMETER |
| 319 | MBM_PACKET_ERROR |
| 320 | MBM_BAD_ADDRESS |
| 321 | |
| 322 | END DESCRIPTION **********************************************************/ |
| 323 | |
| 324 | /*** BeginHeader MBM_WriteCoil */ |
| 325 | int MBM_WriteCoil ( int MB_address, int CoilNbr, int CoilState ); |
| 326 | /*** EndHeader */ |
| 327 | |
| 328 | MODBUS_DEBUG |
| 329 | int MBM_WriteCoil ( int MB_address, int CoilNbr, int CoilState ) |
| 330 | { |
| 331 | auto int ADUStatus; |
| 332 | |
| 333 | if ( CoilState & 0xFFFE ) return MBM_INVALID_PARAMETER; |
| 334 | _initADU( MB_address, 0x05, 4 ); |
| 335 | _insertWord ( CoilNbr ); |
| 336 | _insertWord ( CoilState ); |
| 337 | |
| 338 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 339 | |
| 340 | if ( ADUStatus != MB_SUCCESS ) return MBM_PACKET_ERROR; |
| 341 | if ( mbADU[ADU_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 342 | if ( mbADU[ADU_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 343 | |
| 344 | return MB_SUCCESS; |
| 345 | } // MBM_WriteCoil |
| 346 | |
| 347 | |
| 348 | /* START FUNCTION DESCRIPTION ******************************************** |
| 349 | MBM_WriteReg 0x06 |
| 350 | |
| 351 | SYNTAX: int MBM_WriteReg ( int MB_address, int RegNbr, int RegData ); |
| 352 | |
| 353 | DESCRIPTION: write a value to a single register |
| 354 | |
| 355 | PARAMETER1: MODBUS addresss of the target device |
| 356 | |
| 357 | PARAMETER2: Register number |
| 358 | |
| 359 | PARAMETER3: Regester Data |
| 360 | |
| 361 | RETURN VALUE: MB_SUCCESS |
| 362 | MBM_INVALID_PARAMETER |
| 363 | MBM_PACKET_ERROR |
| 364 | MBM_BAD_ADDRESS |
| 365 | |
| 366 | END DESCRIPTION **********************************************************/ |
| 367 | |
| 368 | /*** BeginHeader MBM_WriteReg */ |
| 369 | int MBM_WriteReg ( int MB_address, int RegNbr, int RegData ); |
| 370 | /*** EndHeader */ |
| 371 | |
| 372 | MODBUS_DEBUG |
| 373 | int MBM_WriteReg ( int MB_address, int RegNbr, int RegData ) |
| 374 | { |
| 375 | auto int ADUStatus; |
| 376 | |
| 377 | _initADU( MB_address, 0x06, 4 ); |
| 378 | _insertWord ( RegNbr ); |
| 379 | _insertWord ( RegData ); |
| 380 | |
| 381 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 382 | |
| 383 | if ( ADUStatus != MB_SUCCESS ) return MBM_PACKET_ERROR; |
| 384 | if ( mbADU[ADU_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 385 | if ( mbADU[ADU_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 386 | |
| 387 | return MB_SUCCESS; |
| 388 | } // MBM_WriteReg |
| 389 | |
| 390 | |
| 391 | /* START FUNCTION DESCRIPTION ******************************************** |
| 392 | MBM_WriteCoils 0x0F |
| 393 | |
| 394 | SYNTAX: int MBM_WriteCoils ( int MB_address, int StartCoilNbr, |
| 395 | int NbrCoils, int CoilStates ); |
| 396 | |
| 397 | DESCRIPTION: write a values to coils |
| 398 | |
| 399 | PARAMETER1: MODBUS addresss of the target device |
| 400 | |
| 401 | PARAMETER2: Starting Coil number |
| 402 | |
| 403 | PARAMETER3: Number of Coils |
| 404 | |
| 405 | PARAMETER4: Coil states - max of 16 with lowest coil nbr value in bit 0 |
| 406 | |
| 407 | RETURN VALUE: MB_SUCCESS |
| 408 | MBM_INVALID_PARAMETER |
| 409 | MBM_PACKET_ERROR |
| 410 | MBM_BAD_ADDRESS |
| 411 | |
| 412 | END DESCRIPTION **********************************************************/ |
| 413 | |
| 414 | /*** BeginHeader MBM_WriteCoils */ |
| 415 | int MBM_WriteCoils ( int MB_address, int StartCoilNbr, int NbrCoils, int CoilStates ); |
| 416 | /*** EndHeader */ |
| 417 | |
| 418 | MODBUS_DEBUG |
| 419 | int MBM_WriteCoils ( int MB_address, int StartCoilNbr, int NbrCoils, int CoilStates ) |
| 420 | { |
| 421 | auto int ADUStatus; |
| 422 | |
| 423 | if ( CoilState & 0xFFFE ) return MBM_INVALID_PARAMETER; |
| 424 | |
| 425 | _initADU( MB_address, 0x0F, 8 ); |
| 426 | _insertWord ( StartCoilNbr ); |
| 427 | _insertWord ( NbrCoils ); |
| 428 | _insertWord ( 2 ); // byte count for up to 16 coils |
| 429 | _insertWord ( CoilStates ); |
| 430 | |
| 431 | ADUStatus = MBM_Send_ADU ( mbADU, pmbADU - mbADU ); |
| 432 | |
| 433 | if ( ADUStatus != MB_SUCCESS ) return MBM_PACKET_ERROR; |
| 434 | if ( mbADU[MBM_OFF_ADDRESS] != MB_address ) return MBM_BAD_ADDRESS; |
| 435 | if ( mbADU[MBM_OFF_FUNCTION] & 0x80 ) return (int)mbADU[ADU_OFF_EXCEPTION]; |
| 436 | |
| 437 | return MB_SUCCESS; |
| 438 | } |
| 439 | |
| 440 | /* START FUNCTION DESCRIPTION ******************************************** |
| 441 | MODBUS_CRC <MODBUS_Slave.LIB> |
| 442 | |
| 443 | SYNTAX: unsigned MODBUS_CRC(unsigned char *pcMess, unsigned wLen) |
| 444 | |
| 445 | DESCRIPTION: alternate CRC calculation |
| 446 | |
| 447 | PARAMETER1: address of bytes for CRC calculation |
| 448 | |
| 449 | PARAMETER2: number of bytes in paraameter1 |
| 450 | |
| 451 | RETURN VALUE: CRC value |
| 452 | |
| 453 | Note: to use this alternate CRC function you must insert |
| 454 | #define USE_MODBUS_CRC |
| 455 | before the #use directives for the modbus libraries. |
| 456 | |
| 457 | END DESCRIPTION **********************************************************/ |
| 458 | |
| 459 | /*** BeginHeader MODBUS_CRC */ |
| 460 | unsigned MODBUS_CRC(unsigned char *pcMess, unsigned wLen); |
| 461 | /*** EndHeader */ |
| 462 | |
| 463 | /*=========================================================================*\ |
| 464 | Compute Cyclic Redundancy Check |
| 465 | \*=========================================================================*/ |
| 466 | |
| 467 | const unsigned char MODBUS_CRC_MSB[] ={ |
| 468 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 469 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 470 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 471 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 472 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 473 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 474 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 475 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 476 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 477 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 478 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 479 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 480 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, |
| 481 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 482 | 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, |
| 483 | 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40 |
| 484 | }; |
| 485 | |
| 486 | const unsigned char MODBUS_CRC_LSB[] ={ |
| 487 | 0x00,0xC0,0xC1,0x01, 0xC3,0x03,0x02,0xC2, 0xC6,0x06,0x07,0xC7, 0x05,0xC5,0xC4,0x04, |
| 488 | 0xCC,0x0C,0x0D,0xCD, 0x0F,0xCF,0xCE,0x0E, 0x0A,0xCA,0xCB,0x0B, 0xC9,0x09,0x08,0xC8, |
| 489 | 0xD8,0x18,0x19,0xD9, 0x1B,0xDB,0xDA,0x1A, 0x1E,0xDE,0xDF,0x1F, 0xDD,0x1D,0x1C,0xDC, |
| 490 | 0x14,0xD4,0xD5,0x15, 0xD7,0x17,0x16,0xD6, 0xD2,0x12,0x13,0xD3, 0x11,0xD1,0xD0,0x10, |
| 491 | 0xF0,0x30,0x31,0xF1, 0x33,0xF3,0xF2,0x32, 0x36,0xF6,0xF7,0x37, 0xF5,0x35,0x34,0xF4, |
| 492 | 0x3C,0xFC,0xFD,0x3D, 0xFF,0x3F,0x3E,0xFE, 0xFA,0x3A,0x3B,0xFB, 0x39,0xF9,0xF8,0x38, |
| 493 | 0x28,0xE8,0xE9,0x29, 0xEB,0x2B,0x2A,0xEA, 0xEE,0x2E,0x2F,0xEF, 0x2D,0xED,0xEC,0x2C, |
| 494 | 0xE4,0x24,0x25,0xE5, 0x27,0xE7,0xE6,0x26, 0x22,0xE2,0xE3,0x23, 0xE1,0x21,0x20,0xE0, |
| 495 | 0xA0,0x60,0x61,0xA1, 0x63,0xA3,0xA2,0x62, 0x66,0xA6,0xA7,0x67, 0xA5,0x65,0x64,0xA4, |
| 496 | 0x6C,0xAC,0xAD,0x6D, 0xAF,0x6F,0x6E,0xAE, 0xAA,0x6A,0x6B,0xAB, 0x69,0xA9,0xA8,0x68, |
| 497 | 0x78,0xB8,0xB9,0x79, 0xBB,0x7B,0x7A,0xBA, 0xBE,0x7E,0x7F,0xBF, 0x7D,0xBD,0xBC,0x7C, |
| 498 | 0xB4,0x74,0x75,0xB5, 0x77,0xB7,0xB6,0x76, 0x72,0xB2,0xB3,0x73, 0xB1,0x71,0x70,0xB0, |
| 499 | 0x50,0x90,0x91,0x51, 0x93,0x53,0x52,0x92, 0x96,0x56,0x57,0x97, 0x55,0x95,0x94,0x54, |
| 500 | 0x9C,0x5C,0x5D,0x9D, 0x5F,0x9F,0x9E,0x5E, 0x5A,0x9A,0x9B,0x5B, 0x99,0x59,0x58,0x98, |
| 501 | 0x88,0x48,0x49,0x89, 0x4B,0x8B,0x8A,0x4A, 0x4E,0x8E,0x8F,0x4F, 0x8D,0x4D,0x4C,0x8C, |
| 502 | 0x44,0x84,0x85,0x45, 0x87,0x47,0x46,0x86, 0x82,0x42,0x43,0x83, 0x41,0x81,0x80,0x40 |
| 503 | }; |
| 504 | |
| 505 | MODBUS_DEBUG |
| 506 | unsigned MODBUS_CRC(unsigned char *pcMess, unsigned wLen) |
| 507 | { |
| 508 | auto unsigned char cHi,cLo; // CRC Accumulators (MSB & LSB) |
| 509 | auto unsigned w; // CRC Shift In Index |
| 510 | |
| 511 | cHi = cLo = 0xFF; // Init CRC |
| 512 | while(wLen--) |
| 513 | { // For Each Byte |
| 514 | w = cHi ^ *pcMess++; // Next Table Index |
| 515 | cHi = cLo ^ MODBUS_CRC_MSB[w]; // Next CRC |
| 516 | cLo = MODBUS_CRC_LSB[w]; |
| 517 | } |
| 518 | return ((unsigned) cHi << 8) | cLo; // merge the bytes and return |
| 519 | } |
| 520 | |
| 521 | /*** BeginHeader */ |
| 522 | #endif // __MBMASTER |
| 523 | /*** EndHeader */ |
| 524 |