/*************************************************************************** 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
*/ class rlModbus { public: /*!
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