ModbusClient.cin

Improved _ModbusReadBits and _ModbusReadRegisters: Check address and curCount against device information
This commit is contained in:
Jonny007-MKD 2014-07-10 07:58:18 +00:00
parent 3e3a24a2a3
commit caf58bd7d6
1 changed files with 82 additions and 24 deletions

View File

@ -78,11 +78,11 @@ variables
// This method prepares anything that sending Modbus requests works. Currently this is only the connection.
// It has to be called by the user/modbus client at the beginning with IP and Port of the Modbus server,
// the timeout value and the number of retries that shall be performed after a timeout
void ModbusInit(char Remote_IP[], word remotePort, word requestTimeout, byte maxRetransmissions)
void ModbusInit(char Remote_IP[], word remotePort, word requestTimeout, byte maxTransmissions)
{
_ModbusConnectTo(Remote_IP, remotePort);
gRequestTimeout = requestTimeout;
gMaxTransmissionCount = maxRetransmissions;
gMaxTransmissionCount = maxTransmissions;
}
// This method cleans up everything: Closes the connection, clears the queues and stops the timer
@ -116,7 +116,7 @@ void ModbusReadInBits(word address, long count)
_ModbusReadBits(ReadBitsIn, address, count);
}
/// <ModbusReadBits>
// This method will submit a request to the Modbus server to read coils
// This method will submit a request to the Modbus server to read discrete inputs
void ModbusReadBits(word address, long count)
{
_ModbusReadBits(ReadBitsIn, address, count);
@ -135,11 +135,38 @@ void _ModbusReadBits(enum ModbusFuncCode funcCode, word address, long count)
byte buffer[length];
word curCount;
struct ModbusReqRead mbreq;
word devStartAddr, devEndAddr;
// FC1: Read Coils (DO), FC2: Read Discret Inputs (DI)
while (count > 0)
// Check the function code. If this method was private we would not need this
switch (funcCode)
{
curCount = count > gMaxBitsPerRead ? gMaxBitsPerRead : count;
case ReadBitsOut:
case ReadBitsIn:
break;
default:
writeDbg(MbError, "_ModbusReadBits: Got incorrect function code 0x%02X!", funcCode);
OnModbusClientPanics(FuncCodeIncorrect);
return;
}
devStartAddr = funcCode == ReadBitsOut ? thisDev.Addr.Read.OutputBits : thisDev.Addr.Read.InputBits; // The start address of the bits
devEndAddr = devStartAddr + thisDev.MaxBitCount; // The address behind the last bit
if (address < devStartAddr) // Oh, reading at the wrong address?
{
writeDbg(MbError, "_ModbusReadBits: The given start address 0x%04X is smaller than the obligatory start address 0x%04X", address, devStartAddr);
OnModbusClientPanics(AddressFailure);
return;
}
// FC1: Read Coils (DO), FC2: Read Discret Inputs (DI)
while (count > 0 && address < devEndAddr)
{
curCount = count > gMaxBitsPerRead ? gMaxBitsPerRead : count; // divide packets that are too large
if (address + curCount > devEndAddr) // upper bound in process image
{
writeDbg(MbWarning, "_ModbusReadBits: Impossible to read %d bits at 0x%04X. Changed count to %d.", curCount, address, devEndAddr - address);
curCount = devEndAddr - address;
}
_ModbusMakeHeader(mbreq.Header, length, funcCode);
mbreq.Address = address; // [2] Start address
@ -219,15 +246,45 @@ void _ModbusReadRegisters(enum ModbusFuncCode funcCode, word address, long count
byte buffer[length];
word curCount;
struct ModbusReqRead mbreq;
word devStartAddr, devEndAddr; // Check the function code. If this method was private we would not need this
// FC3: Read Holding Registers (AO), FC4: Read Input Registers (AI)
while (count > 0)
switch (funcCode)
{
curCount = count > gMaxRegsPerRead ? gMaxRegsPerRead : count;
case ReadRegistersOut:
case ReadRegistersIn:
break;
default:
writeDbg(MbError, "_ModbusReadRegisters: Got incorrect function code 0x%02X!", funcCode);
OnModbusClientPanics(FuncCodeIncorrect);
return;
}
devStartAddr = funcCode == ReadRegistersOut ? thisDev.Addr.Read.OutputRegisters : thisDev.Addr.Read.InputRegisters; // The start address of the bits
devEndAddr = devStartAddr + thisDev.MaxRegisterCount; // The address behind the last register
if (address >= devEndAddr)
devEndAddr = 0xFFFF; // Some other address. We might be reading extra registers (no input)
if (address < devStartAddr) // Oh, reading at the wrong address?
{
writeDbg(MbError, "_ModbusReadRegisters: The given start address 0x%04X is smaller than the obligatory start address 0x%04X", address, devStartAddr);
OnModbusClientPanics(AddressFailure);
return;
}
// FC3: Read Holding Registers (AO), FC4: Read Input Registers (AI)
while (count > 0 && address < devEndAddr)
{
curCount = count > gMaxRegsPerRead ? gMaxRegsPerRead : count; // divide packets that are too large
if (address + curCount > devEndAddr) // upper bound in process image
{
writeDbg(MbWarning, "_ModbusReadBits: Impossible to read %d bits at 0x%04X. Changed count to %d.", curCount, address, devEndAddr - address);
curCount = devEndAddr - address;
}
write("address = 0x%04X, count = %d, curCount = %d, devStartAddr = 0x%04X, devEndAddr = 0x%04X", address, count, curCount, devStartAddr, devEndAddr);
_ModbusMakeHeader(mbreq.Header, length, funcCode);
mbreq.Address = address; // [2] Start address
mbreq.Count = curCount; // [2] Number of items; 1:max 125=0x7D
mbreq.Count = curCount; // [2] Number of items; 1:max 125=0x7D
writeDbg(MbDebug, "Sending 'Read Registers' (0x03) command. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address, curCount);
@ -378,7 +435,7 @@ void ModbusWriteBits(word address, long count, byte values[])
struct ModbusReqWriteBits mbreq;
word curCount;
byte dataLength;
byte overallLength;
word overallLength;
word i;
long offset;
@ -406,7 +463,7 @@ void ModbusWriteBits(word address, long count, byte values[])
for (i = 0; i < dataLength; i++) // [264] Byte status, 8 per byte
mbreq.Data[i] = values[i+offset/8];
writeDbg(MbDebug, "Sending 'Write Bits' (0x0F) command. Addr: 0x%04X, Count: %d", address, curCount);
writeDbg(MbDebug, "Sending 'Write Bits' (0x0F) command. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address, curCount);
memcpy_h2n(buffer, mbreq);
_ModbusSend(buffer, overallLength, mbreq.Header.TxID);
@ -423,17 +480,14 @@ void ModbusWriteBits(word address, long count, byte values[])
void ModbusWriteBitsB(word address, long count, byte values[])
{
byte buffer[0x4000/8]; // Maximum value from B&R devices. *sigh*
word length;
long length;
dword ellCount;
dword i;
byte j;
char str1[20*2], str2[20*3];
length = (word)_ceil(count / 8.0);
writeDbg(AlgoDebug, "ModbusWriteBitsB: count: %d; length: %d", count, length);
if (count % 8 != 0)
length--;
length = (long)_floor(count / 8.0);
writeDbg(AlgoDebug, "ModbusWriteBitsB: count: %d; length: %d", count, length+1);
for (i = 0; i < length; i++)
{
@ -441,20 +495,20 @@ void ModbusWriteBitsB(word address, long count, byte values[])
for (j = 0; j < 8; j++)
{
buffer[i] |= (values[i*8 + j] & 0x01) << j;
writeDbg(AlgoDebug, "ModbusWriteBitsB: j: %d; indx: %d; value: %d; mask: %X", j, i*8 + j, values[i*8 + j], (0x01 << j));
writeDbg(AlgoDebug, "ModbusWriteBitsB: j: %d; indx: %d; value: %d; mask: %X", j, i*8 + j, values[i*8 + j], (0x01 << j));
}
writeDbg(AlgoDebug, "ModbusWriteBitsB: %d: %X", i, buffer[i]);
writeDbg(AlgoDebug, "ModbusWriteBitsB: Byte %d = %X", i, buffer[i]);
}
for (j = 0; j < count % 8; j++) // wont be executed if there is no remainder
{
writeDbg(AlgoDebug, "ModbusWriteBitsB: j: %d; indx: %d; value: %d; mask: %X", j, (length-1)*8 + j, values[(length-1)*8 + j], (0x01 << j));
buffer[length] |= (values[(length)*8 + j] & 0x01) << j;
writeDbg(AlgoDebug, "ModbusWriteBitsB: j: %d; indx: %d; value: %d; mask: %X", j, i*8 + j, values[i*8 + j], (0x01 << j));
buffer[i] |= (values[(i)*8 + j] & 0x01) << j;
}
writeDbg(AlgoDebug, "ModbusWriteBitsB: %d: %X", length-1, buffer[length-1]);
writeDbg(AlgoDebug, "ModbusWriteBitsB: Byte %d = %X", i, buffer[i]);
hbin_to_strhex(values, str1);
bin_to_strhex(buffer, str2);
writeDbg(AlgoDebug, "ModbusWriteBitsB: Encoded %s to %s", str1, str2);
writeDbg(AlgoDebug, "ModbusWriteBitsB: Encoded %s to %s (%d -> %d)", str1, str2, count, length);
ModbusWriteBits(address, count, buffer);
}
@ -555,6 +609,10 @@ void _OnModbusConfirmRegistersException(struct ModbusApHeader mbap, enum ModbusE
// REGION: ModbusWriteMasks ------------------------------------------------------------
/// <ModbusWriteMasks>
// This method will submit a request to the Modbus server to mask a holding registers
/// The register will be using the following rule:
/// Result = (Content & AndMask) | (Content & !AndMask)
/// This means, you must not AND the bits you are trying to OR.
/// Example: You want to OR the 4th bit --> AND = 0xFFFB, OR = 0x0004
void ModbusWriteMasks(word address, word and, word or)
{
const word length = __size_of(struct ModbusReqWriteMasks);