ModbusClient.cin

Improved comments
  Added functionality for Modbus Exception 0x05 (ACK)

ModbusClient.cin
ModbusStructs.cin
  Moved Modbus Exception descriptions from ModbusClient.cin to ModbusStructs.cin
This commit is contained in:
Jonny007-MKD 2014-08-29 15:25:22 +00:00
parent f97e0c7481
commit 63f252d32e
2 changed files with 86 additions and 38 deletions

View File

@ -3,52 +3,93 @@
// This is the main file providing functions for talking to Modbus servers.
// Additionally include a network layer: ModbusUdp.cin, ModbusTcp.cin or ModbusEil.cin
/// This layer provides functions to send Modbus requests, enqueues these messages and watch for timeouts. When responses are received, the corresponding callback method will be called
/// There are three queues available: Pending, Sent & Ack. Only the latter shall be used by the higher layer. Pending telegrams are waiting to be sent, sent telegrams are waiting to be responded and acknowledged telegrams were already responded and can now be processed further.
/// This layer provides functions to send Modbus requests, enqueues these messages and watches for timeouts. When responses are received, the corresponding callback method will be called
/// There are three queues available: Pending, Sent & Ack. Only the latter (gQueueAck) shall be used by the higher layer. Pending telegrams are waiting to be sent, sent telegrams are waiting to be responded and acknowledged telegrams were already responded and can now be processed further.
/// The Modbus telegrams are distinguished in the queues by their TxID
/// It provides following methods
/// This Modbus Client file provides following methods
/// - ModbusInit() Prepare anything that Modbus works (open connection etc.)
/// - ModbusEnd() Client up everything (close connection etc.)
/// - ModbusEnd() Clean up everything (close connection etc.)
/// - ModbusReadOutBits() Modbus Function Code: 0x01 (Discrete inputs)
/// - ModbusReadInBits() Modbus Function Code: 0x02 (Coils)
/// --> results in OnModbusReadBitsSuccess() or OnModbusReadBitsFailed() (have to be implemented by you)
/// - ModbusReadOutBits() Modbus Function Code: 0x01 (Read Discrete inputs)
/// - ModbusReadInBits() Modbus Function Code: 0x02 (Read Coils)
/// --> results in OnModbusReadBitsSuccess() or OnModbusReadBitsFailed() (have to be implemented by the higher layer)
/// - ModbusReadOutRegisters() Modbus Function Code: 0x03 (Input registers)
/// - ModbusReadInRegisters() Modbus Function Code: 0x04 (Holding registers)
/// --> results in OnModbusReadRegistersSuccess() or OnModbusReadRegistersFailed() (have to be implemented by you)
/// - ModbusReadOutRegisters() Modbus Function Code: 0x03 (Read Input registers)
/// - ModbusReadInRegisters() Modbus Function Code: 0x04 (Read Holding registers)
/// --> results in OnModbusReadRegistersSuccess() or OnModbusReadRegistersFailed() (have to be implemented by the higher layer)
/// - ModbusWriteBit() Modbus Function Code: 0x05 (Coils)
/// --> results in OnModbusWriteBitSuccess() or OnModbusWriteBitFailed() (have to be implemented by you)
/// - ModbusWriteBit() Modbus Function Code: 0x05 (Write Coil)
/// --> results in OnModbusWriteBitSuccess() or OnModbusWriteBitFailed() (have to be implemented by the higher layer)
/// - ModbusWriteRegister() Modbus Function Code: 0x06 (Holding registers)
/// --> results in OnModbusWriteRegisterSuccess() or OnModbusWriteRegisterFailed() (have to be implemented by you)
/// - ModbusWriteRegister() Modbus Function Code: 0x06 (Write Holding register)
/// --> results in OnModbusWriteRegisterSuccess() or OnModbusWriteRegisterFailed() (have to be implemented by the higher layer)
/// - ModbusWriteBits() Modbus Function Code: 0x0F (Coils)
/// - ModbusWriteBits() Modbus Function Code: 0x0F (Write multiple Coils)
/// - ModbusWriteBitsB() Wrapper for ModbusWriteBits: Encodes a bit array with size N to an array with size N/8
/// --> results in OnModbusWriteBitsSuccess() or OnModbusWriteBitsFailed() (have to be implemented by you)
/// --> results in OnModbusWriteBitsSuccess() or OnModbusWriteBitsFailed() (have to be implemented by the higher layer)
/// - ModbusWriteRegisters() Modbus Function Code: 0x10 (Holding registers)
/// - ModbusReadWriteRegisters() Modbus Function Code: 0x17 (Holding registers)
/// --> results in OnModbusWriteRegistersSuccess() or OnModbusWriteRegistersFailed() (have to be implemented by you)
/// - ModbusWriteRegisters() Modbus Function Code: 0x10 (Write multiple Holding registers)
/// - ModbusReadWriteRegisters() Modbus Function Code: 0x17 (Read/Write multiple Holding registers)
/// --> results in OnModbusWriteRegistersSuccess() or OnModbusWriteRegistersFailed() (have to be implemented by the higher layer)
/// - ModbusWriteMasks() Modbus Function Code: 0x10 (Mask Write Holding registers)
/// --> results in OnModbusWriteMasksSuccess() or OnModbusWriteMasksFailed() (have to be implemented by the higher layer)
/// Additionally the highest layer have to implement OnModbusClientPanics() which all layers will call and pass errors. The highest layer may decide what to do with this error.
/// Methods that have to be implemented by the higher layer are:
///// This method gets called when an error occured while trying to read some bits (ModbusReadBits())
///void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to read some registers (ModbusReadRegisters())
///void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to set a bit (ModbusWriteBit())
///void OnModbusWriteBitFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to set a register (ModbusWriteRegister())
///void OnModbusWriteRegisterFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to apply a mask on a register (ModbusWriteMask())
///void OnModbusWriteMasksFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to read and write registers (ModbusReadWriteRegisters())
///void OnModbusReadWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to set multiple bits (ModbusWriteBits())
///void OnModbusWriteBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when an error occured while trying to set multiple registers (ModbusWriteRegisters())
///void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
///// This method gets called when some bits were read successfully. See 'bitStatus' for their values and 'mbreq.Address' for their start address
///void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq){}
///// This method gets called when some bits were read successfully. See 'mbres.Data' for their values and 'mbreq.Address' for their start address
///void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq){}
///// This method gets called when a bit was set successfully.
///void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbres){}
///// This method gets called when a register was set successsfully.
///void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbres){}
///// This method gets called when multiple bits were set successfully.
///void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbres){}
///// This method gets called when multiple registers were set successfully.
///void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbres){}
///// This method gets called when a mask was applied successfully.
///void OnModbusWriteMasksSuccess(struct ModbusResConfirmMasks mbres){}
///
///// This method gets called when the Modbus Client panics (saying a fatal error occured).
///// It will pass as argument what happened. Please see the log (increase debug level in preStart) for more details.
///void OnModbusClientPanics(enum FatalErrors reason){}
/// - ModbusWriteMasks() Modbus Function Code: 0x10 (Holding registers)
/// --> results in OnModbusWriteMasksSuccess() or OnModbusWriteMasksFailed() (have to be implemented by you)
includes
{
#include "ModbusStructs.cin"
#include "ModbusStructs.cin" // We only depend on the structures
// The network layer will be included by the higher layer
}
variables
{
msTimer gtModbusRobin; // Timer that sends the packets and watches for timeouts
word gTxID = 0x0000; // Transaction Identifier for Modbus. Used as index for gQueue
word gTxID = 0x0000; // Transaction Identifier for the next Modbus packet. Used as index for gQueue
word gRequestTimeout; // Timeout of a packet [ms]
byte gMaxTransmissionCount; // Maximum number of transmissions (after timeouts)
// Global storage for pending and sent requests, associated by TxID
// Storage element for pending, sent and acknowledge requests, associated by TxID
struct QueueElement
{
word TimeoutTicks; // Time counter [ms]. Used to watch for timeouts (see gRequestTimeout)
@ -57,23 +98,10 @@ variables
word Length;
byte Buffer[gModbusMaxTelegramSize];
};
// Storages with these requests
struct QueueElement gQueuePending[long, 2];
struct QueueElement gQueueSent[long, 2];
struct QueueElement gQueueAck[long, 2];
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"
};
}
// This method prepares anything that sending Modbus requests works. Currently this is only the connection.
@ -894,6 +922,12 @@ void _OnModbusReceive2Exceptions(byte exCode, struct ModbusApHeader mbap)
enum ModbusException ex;
ex = (enum ModbusException)exCode;
if (ex == Acknowledge) // An ACK resets the timeout timer
{
gQueueSent[mbap.TxID].TimeoutTicks = 0;
return;
}
// else report the error to the corresponding function
switch (mbap.FuncCode)
{
case 0x80+ReadBitsOut:

View File

@ -152,6 +152,20 @@ variables
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