ModbusClient.cin
Improved _ModbusReadBits and _ModbusReadRegisters: Check address and curCount against device information
This commit is contained in:
parent
3e3a24a2a3
commit
caf58bd7d6
1 changed files with 82 additions and 24 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue