Jonny007-MKD
63f252d32e
Improved comments Added functionality for Modbus Exception 0x05 (ACK) ModbusClient.cin ModbusStructs.cin Moved Modbus Exception descriptions from ModbusClient.cin to ModbusStructs.cin
182 lines
5.1 KiB
Plaintext
182 lines
5.1 KiB
Plaintext
/*@!Encoding:1252*/
|
|
variables
|
|
{
|
|
// Constant maximum values according to Modbus Specification v1.1
|
|
const word gMaxBitsPerRead = 2000;
|
|
const word gMaxRegsPerRead = 125;
|
|
const word gMaxBitsPerWrite = 1968; // Multiple of 8!
|
|
const word gMaxRegsPerWrite = 123;
|
|
|
|
// Function Codes according to Modbus Specification v1.1
|
|
enum ModbusFuncCode
|
|
{
|
|
ReadBitsOut = 0x01, // Read Coils
|
|
ReadBitsIn = 0x02, // Read Discrete Inputs
|
|
ReadRegistersOut = 0x03, // Read Holding Registers
|
|
ReadRegistersIn = 0x04, // Read Input Registers
|
|
WriteBit = 0x05, // Write Single Coil
|
|
WriteRegister = 0x06, // Write Single Holding Register
|
|
WriteBits = 0x0F, // Write Multiple Coils
|
|
WriteRegisters = 0x10, // Write Multiple Holding Registers
|
|
MaskRegister = 0x16, // Mask Write Holding Register
|
|
ReadWriteRegisters = 0x17 // Read/Write Multiple Registers
|
|
};
|
|
|
|
// Modbus Application Header
|
|
// Every Modbus Packet begins with these 7 (+FuncCode) Bytes
|
|
_align(1) struct ModbusApHeader
|
|
{
|
|
word TxID;
|
|
word Protocol;
|
|
word Length;
|
|
byte UnitID;
|
|
byte FuncCode;
|
|
};
|
|
|
|
/// Request structures following
|
|
// Read Data from the host. We only need the start address and the number of bits/registers we want to read
|
|
_align(1) struct ModbusReqRead
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word Count;
|
|
};
|
|
// Write a single value to a bit/register
|
|
_align(1) struct ModbusReqWriteSingle
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word Value;
|
|
};
|
|
// Write several values to a bit/register starting with Address
|
|
_align(1) struct ModbusReqWriteBits
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word Count;
|
|
byte ByteCount;
|
|
byte Data[gMaxBitsPerWrite/8]; // Max length: 1968 bits
|
|
};
|
|
// Write several values to bits starting with Address
|
|
_align(1) struct ModbusReqWriteRegisters
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word Count;
|
|
byte ByteCount;
|
|
word Data[gMaxRegsPerWrite]; // Max length: 123 registers
|
|
};
|
|
// Write AND and OR masks to a holding register
|
|
_align(1) struct ModbusReqWriteMasks
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word And;
|
|
word Or;
|
|
};
|
|
// Read and write multiple registers
|
|
_align(1) struct ModbusReqReadWriteRegisters
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word ReadAddress;
|
|
word ReadCount;
|
|
word WriteAddress;
|
|
word WriteCount;
|
|
byte ByteCount;
|
|
word Data[gMaxRegsPerWrite-2]; // Max length: 123-2 registers
|
|
};
|
|
|
|
|
|
/// Response structures following
|
|
// Receive several bit values
|
|
_align(1) struct ModbusResReceiveBits
|
|
{
|
|
struct ModbusApHeader Header;
|
|
byte ByteCount;
|
|
byte Data[gMaxBitsPerRead/8]; // Max length: 2000 bits
|
|
};
|
|
// Receive several register values
|
|
_align(1) struct ModbusResReceiveRegisters
|
|
{
|
|
struct ModbusApHeader Header;
|
|
byte ByteCount;
|
|
word Data[gMaxRegsPerRead]; // Max length: 125 registers
|
|
};
|
|
// Confirm the write of a single bit/register
|
|
_align(1) struct ModbusResConfirmSingle
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
int Value;
|
|
};
|
|
// Confirm the write of several bits/registers
|
|
_align(1) struct ModbusResConfirmMultiple
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word Count;
|
|
};
|
|
// Confirm the write of AND and OR mask
|
|
_align(1) struct ModbusResConfirmMasks
|
|
{
|
|
struct ModbusApHeader Header;
|
|
word Address;
|
|
word And;
|
|
word Or;
|
|
};
|
|
|
|
// The maximum modbus telegram size.
|
|
// Several telegrams use this many bytes, but CAPL does not support a constant max function to let it calculate it. So we use ModbusResReceiveRegisters
|
|
const word gModbusMaxTelegramSize = __size_of(struct ModbusResReceiveRegisters);
|
|
|
|
|
|
// Some errors that may occur when sending a request
|
|
enum ModbusRequestError
|
|
{
|
|
Exception, // Modbus exception was returned
|
|
Timeout, // Timeout occured, resending the packet
|
|
FinalTimeout, // Timeout occured, not resending the packet
|
|
NotSent // Sending the packet was impossible
|
|
};
|
|
|
|
// Modbus exception codes according to Modbus Specification v1.1
|
|
enum ModbusException
|
|
{
|
|
None = 0x00,
|
|
IllegalFuncCode = 0x01,
|
|
IllegalDataAddress = 0x02,
|
|
IllegalDataValue = 0x03,
|
|
ServerFailure = 0x04,
|
|
Acknowledge = 0x05,
|
|
ServerBusy = 0x06,
|
|
GatewayPathsNA = 0x0A,
|
|
TargetOffline = 0x0B
|
|
};
|
|
// Modbus Exception descriptions
|
|
char ModbusExceptions[11][72] = {
|
|
"Illegal func code (0x01). The function code is unknown by the server",
|
|
"Illegal data address (0x02). Please check your configuration",
|
|
"Illegal data value (0x03)",
|
|
"Server failure (0x04). The server failed during execution",
|
|
"Acknowledge (0x05). The server needs more time to generate the response",
|
|
"Server busy (0x06). The request could not be accepted",
|
|
"",
|
|
"",
|
|
"",
|
|
"Gateway problem (0x0A). Gateway paths not available",
|
|
"Gateway problem (0x0B). The targeted device failed to respond"
|
|
};
|
|
|
|
// Fatal errors that may stop the code execution
|
|
enum FatalErrors
|
|
{
|
|
ParsingBuffer,
|
|
ModbusPackageWasSplit,
|
|
DeviceCodeUnknown,
|
|
VendorIdUnknown,
|
|
ConnectionError,
|
|
FuncCodeIncorrect,
|
|
AddressFailure,
|
|
SwitchArgumentInvalid
|
|
};
|
|
} |