/*************************************************************************** rlmodbus.h - description ------------------- begin : Tue Mar 13 2003 copyright : (C) 2003 by R. Lehrig email : lehrig@t-online.de ***************************************************************************/ /*************************************************************************** * * * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as * * published by the Free Software Foundation * * * ***************************************************************************/ #ifndef _RL_MODBUS_H_ #define _RL_MODBUS_H_ #include "rldefine.h" #include "rlsocket.h" #include "rlserial.h" /*!
This class implements the modbus protocol. You can use serial interfaces or TCP/IP. Modbus RTU and ASCII are available. All Modbus requests include "slave" and "function". Then some bytes follow, which are specific to a given function. The request is then terminated by a checksum. This table shows the bytes that are specific to a given function.
| Function | Query | Response | |
| 01 Read Coil Status | Start adr high Start adr low Number of points high Number of points low |
Data Byte Count Data1 Data2 … |
8 points per byte |
| 02 Read Input Status | Start adr high Start adr low Number of points high Number of points low |
Data Byte Count Data1 Data2 … |
8 points per byte |
| 03 Read Holding Registers | Start adr high Start adr low Number of points high Number of points low |
Data Byte Count Data1 high Data1 low Data2 high Data2 low… |
1 point needs 2 bytes |
| 04 Read Input Registers | Start adr high Start adr low Number of points high Number of points low |
Data Byte Count Data1 high Data1 low Data2 high Data2 low… |
1 point needs 2 bytes |
| 05 Force Single Coil | Coil adr high Coil adr low Force data high Force data low |
Coil adr high Coil adr low Force data high Force data low |
Force data ON = 0x0ff00 Force data OFF = 0 |
| 06 Preset Single Register | Register adr high Register adr low Preset data high Preset data low |
Register adr high Register adr low Preset data high Preset data low |
|
| 07 Read Exception Status | Coil data | 8 exception status coils returned | |
| 11 Fetch Comm Event Counter | Status high Status low Event Count high Event Count low |
||
| 12 Fetch Comm Event Log | See: PI_MODBUS_300.pdf | ||
| 15 Force Multiple Coils | Coil adr high Coil adr low Number of coils high Number of coils low Force data byte count Force data1 Force data2 ... |
Coil adr high Coil adr low Number of coils high Number of coils low |
8 coils per byte |
| 16 Preset Multiple Registers | Start adr high Start adr low Number of registers high Number of registers low Data byte count Data1 high Data1 low Data2 high Data2 low … |
Start adr high Start adr low Number of registers high Number of registers low |
|
| 17 Report Slave ID | Data Byte count ~ device specific | See: PI_MODBUS_300.pdf | |
| 20 Read General Reference | See: PI_MODBUS_300.pdf | ||
| 21 Write General Reference | See: PI_MODBUS_300.pdf | ||
| 22 Mask Write 4X Register | See: PI_MODBUS_300.pdf | ||
| 23 Read/Write 4X Registers | See: PI_MODBUS_300.pdf | ||
| 24 Read FIFO Queue | See: PI_MODBUS_300.pdf |
data exchanged by Modbus is either:
1byte unsigned for coils
2byte unsigned for registers
Helper union for converting Modbus data to data types that are not standard Modbus data types
Example:
rlModbus::DATA data;
data.u_short[0] = registers[0]; // store an unsigned 16 bit register in union data
printf("print registers[0] as signed int value=%d\n", data.s_short[0]);
*/
typedef union
{
unsigned char u_char[4]; // 4 * 8bit_data, unsigned
char s_char[4]; // 4 * 8bit_data, signed
unsigned short u_short[2]; // 2 * 16bit_data, signed
short s_short[2]; // 2 * 16bit_data, signed
unsigned int u_int; // 1 * 32bit_data, unsigned
int s_int; // 1 * 32bit_data, signed
float s_float; // 1 * 32bit_data, signed
}DATA;
enum Modbus
{
MODBUS_CHECKSUM_ERROR = -2,
MODBUS_ERROR = -1,
MODBUS_SUCCESS = 0,
MODBUS_RTU = 1,
MODBUS_ASCII = 2
};
enum ModbusFunctionCodes
{
ReadCoilStatus = 1,
ReadInputStatus = 2,
ReadHoldingRegisters = 3,
ReadInputRegisters = 4,
ForceSingleCoil = 5,
PresetSingleRegister = 6,
ReadExceptionStatus = 7,
FetchCommEventCtr = 11,
FetchCommEventLog = 12,
ForceMultipleCoils = 15,
PresetMultipleRegs = 16,
ReportSlaveID = 17,
ReadGeneralReference = 20,
WriteGeneralReference = 21,
MaskWrite4XRegisters = 22,
ReadWrite4XRegisters = 23,
ReadFifoQueue = 24
};
rlModbus(long max_telegram_length = 1024, int mode = MODBUS_RTU, char end_delimitor = 0x0a);
virtual ~rlModbus();
int write (int slave, int function, const unsigned char *data, int len, int *transactionID = NULL);
int request (int slave, int function, int start_adr, int num_register);
int response(int *slave, int *function, unsigned char *data, int timeout=1000);
int readRequest(int *slave, int *function, unsigned char *data, int timeout=1000, int *transactionID = NULL);
void registerSocket(rlSocket *socket);
void registerSerial(rlSerial *serial);
int data2int(const unsigned char *data);
int int2data(int val, unsigned char *data);
int intsize();
int autoreconnectSocket;
int readCoilStatus (int slave, int start_adr, int number_of_coils, unsigned char *status, int timeout=1000);
int readInputStatus (int slave, int start_adr, int number_of_inputs, unsigned char *status, int timeout=1000);
/*! We assume positive values for registers: 0 <= registers < 256*256*/ int readHoldingRegisters (int slave, int start_adr, int number_of_registers, int *registers, int timeout=1000); /*!
We assume positive values for registers: 0 <= registers < 256*256*/ int readInputRegisters (int slave, int start_adr, int number_of_registers, int *registers, int timeout=1000); int forceSingleCoil (int slave, int coil_adr, int value, int timeout=1000); /*!
We assume positive values for registers: 0 <= value < 256*256*/ int presetSingleRegister (int slave, int register_adr, int value, int timeout=1000); /*!
We assume positive values for registers: 0 <= registers < 256*256*/ int forceMultipleCoils (int slave, int coil_adr, int number_of_coils, unsigned char *coils, int timeout=1000); /*!
We assume positive values for registers: 0 <= registers < 256*256*/ int presetMultipleRegisters (int slave, int start_adr, int number_of_registers, int *registers, int timeout=1000); private: int buf2int_rtu(unsigned char *buf); void int2buf_rtu(int i, unsigned char *buf); int buf2int_ascii(unsigned char *buf); void int2buf_ascii(int i, unsigned char *buf); void insertLRC(int len); void insertCRC(int len); int LRCerror(int len); int CRCerror(int len); rlSocket *s; rlSerial *tty; unsigned char *tel; long maxtel; int mode; char delimitor; }; #endif