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

View file

@ -78,11 +78,11 @@ variables
// This method prepares anything that sending Modbus requests works. Currently this is only the connection. // 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, // 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 // 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); _ModbusConnectTo(Remote_IP, remotePort);
gRequestTimeout = requestTimeout; gRequestTimeout = requestTimeout;
gMaxTransmissionCount = maxRetransmissions; gMaxTransmissionCount = maxTransmissions;
} }
// This method cleans up everything: Closes the connection, clears the queues and stops the timer // 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(ReadBitsIn, address, count);
} }
/// <ModbusReadBits> /// <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) void ModbusReadBits(word address, long count)
{ {
_ModbusReadBits(ReadBitsIn, address, count); _ModbusReadBits(ReadBitsIn, address, count);
@ -135,11 +135,38 @@ void _ModbusReadBits(enum ModbusFuncCode funcCode, word address, long count)
byte buffer[length]; byte buffer[length];
word curCount; word curCount;
struct ModbusReqRead mbreq; struct ModbusReqRead mbreq;
word devStartAddr, devEndAddr;
// FC1: Read Coils (DO), FC2: Read Discret Inputs (DI) // Check the function code. If this method was private we would not need this
while (count > 0) 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); _ModbusMakeHeader(mbreq.Header, length, funcCode);
mbreq.Address = address; // [2] Start address mbreq.Address = address; // [2] Start address
@ -219,15 +246,45 @@ void _ModbusReadRegisters(enum ModbusFuncCode funcCode, word address, long count
byte buffer[length]; byte buffer[length];
word curCount; word curCount;
struct ModbusReqRead mbreq; 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) switch (funcCode)
while (count > 0)
{ {
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); _ModbusMakeHeader(mbreq.Header, length, funcCode);
mbreq.Address = address; // [2] Start address 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); 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; struct ModbusReqWriteBits mbreq;
word curCount; word curCount;
byte dataLength; byte dataLength;
byte overallLength; word overallLength;
word i; word i;
long offset; 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 for (i = 0; i < dataLength; i++) // [264] Byte status, 8 per byte
mbreq.Data[i] = values[i+offset/8]; 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); memcpy_h2n(buffer, mbreq);
_ModbusSend(buffer, overallLength, mbreq.Header.TxID); _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[]) void ModbusWriteBitsB(word address, long count, byte values[])
{ {
byte buffer[0x4000/8]; // Maximum value from B&R devices. *sigh* byte buffer[0x4000/8]; // Maximum value from B&R devices. *sigh*
word length; long length;
dword ellCount; dword ellCount;
dword i; dword i;
byte j; byte j;
char str1[20*2], str2[20*3]; char str1[20*2], str2[20*3];
length = (word)_ceil(count / 8.0); length = (long)_floor(count / 8.0);
writeDbg(AlgoDebug, "ModbusWriteBitsB: count: %d; length: %d", count, length); writeDbg(AlgoDebug, "ModbusWriteBitsB: count: %d; length: %d", count, length+1);
if (count % 8 != 0)
length--;
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ {
@ -441,20 +495,20 @@ void ModbusWriteBitsB(word address, long count, byte values[])
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
buffer[i] |= (values[i*8 + j] & 0x01) << 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 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)); writeDbg(AlgoDebug, "ModbusWriteBitsB: j: %d; indx: %d; value: %d; mask: %X", j, i*8 + j, values[i*8 + j], (0x01 << j));
buffer[length] |= (values[(length)*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); hbin_to_strhex(values, str1);
bin_to_strhex(buffer, str2); 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); ModbusWriteBits(address, count, buffer);
} }
@ -555,6 +609,10 @@ void _OnModbusConfirmRegistersException(struct ModbusApHeader mbap, enum ModbusE
// REGION: ModbusWriteMasks ------------------------------------------------------------ // REGION: ModbusWriteMasks ------------------------------------------------------------
/// <ModbusWriteMasks> /// <ModbusWriteMasks>
// This method will submit a request to the Modbus server to mask a holding registers // 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) void ModbusWriteMasks(word address, word and, word or)
{ {
const word length = __size_of(struct ModbusReqWriteMasks); const word length = __size_of(struct ModbusReqWriteMasks);