Moved all sysvars to PollingModbusClient.can
Fixed bug when splitting Modbus write requests
This commit is contained in:
parent
b6f211d5d3
commit
2df8f31eb7
2 changed files with 40 additions and 17 deletions
|
@ -31,7 +31,7 @@ on start
|
|||
DeviceInit(@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::Vendor); // Set all device specific parameters (Wago / B&R)
|
||||
|
||||
writeDbg(MbInfo, "Connecting to %s:%d", ip, @sysvar::Config::Modbus::Port);
|
||||
ModbusInit(ip, @sysvar::Config::Modbus::Port); // Connect to device. Opens socket and connection or what ever
|
||||
ModbusInit(ip, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, @sysvar::Config::Modbus::MaxTransmissionCount); // Connect to device. Opens socket and connection or what ever
|
||||
|
||||
ModbusReadOutBits(gDevOutputBitAddrR, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits); // Read the start status of the output bits
|
||||
ModbusReadOutRegisters(gDevOutputRegAddrR, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters); // Read the start status of the output registers
|
||||
|
|
|
@ -44,11 +44,13 @@ 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 gRequestTimeout; // Timeout of a packet [ms]
|
||||
byte gMaxTransmissionCount; // Maximum number of transmissions (after timeouts)
|
||||
|
||||
// Global storage for pending and sent requests, associated by TxID
|
||||
struct QueueElement
|
||||
{
|
||||
word TimeoutTicks; // Time counter [ms]. Used to watch for timeouts (see @sysvar::Config::Modubs::RequestTimeout)
|
||||
word TimeoutTicks; // Time counter [ms]. Used to watch for timeouts (see gRequestTimeout)
|
||||
byte Timeouts;
|
||||
word Length;
|
||||
byte Buffer[gModbusMaxTelegramSize];
|
||||
|
@ -73,10 +75,13 @@ 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
|
||||
void ModbusInit(char Remote_IP[], word remotePort)
|
||||
// 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)
|
||||
{
|
||||
_ModbusConnectTo(Remote_IP, remotePort);
|
||||
gRequestTimeout = requestTimeout;
|
||||
gMaxTransmissionCount = maxRetransmissions;
|
||||
}
|
||||
|
||||
// This method fills the ModbusApHeader structure 'mbap'.
|
||||
|
@ -364,6 +369,7 @@ void ModbusWriteBits(word address, long count, byte values[])
|
|||
byte dataLength;
|
||||
byte overallLength;
|
||||
word i;
|
||||
long offset;
|
||||
|
||||
// FC15: Write Multiple Bits (DOs)
|
||||
while (count > 0)
|
||||
|
@ -380,12 +386,18 @@ void ModbusWriteBits(word address, long count, byte values[])
|
|||
dataLength = _ceil(curCount / 8.0);
|
||||
overallLength = maxLength - gMaxBitsPerWrite/8 + dataLength;
|
||||
}
|
||||
if (curCount == 1)
|
||||
{
|
||||
ModbusWriteBit(address+offset, values[offset/8]);
|
||||
return;
|
||||
}
|
||||
_ModbusMakeHeader(mbreq.Header, overallLength, funcCode);
|
||||
|
||||
mbreq.Address = address; // [2] Output address
|
||||
mbreq.Address = address+offset; // [2] Output address
|
||||
mbreq.Count = curCount; // [2] Number of items; 1:max 1968=0x7B0
|
||||
mbreq.ByteCount = dataLength; // [1] Number of bytes; = ceil(count/8)
|
||||
memcpy(mbreq.Data, values, dataLength); // [246] Data; this is 1 unneccessary memcpy :( Well, readability...
|
||||
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);
|
||||
|
||||
|
@ -393,7 +405,7 @@ void ModbusWriteBits(word address, long count, byte values[])
|
|||
_ModbusSend(buffer, overallLength, mbreq.Header.TxID);
|
||||
|
||||
count -= gMaxBitsPerWrite;
|
||||
address += gMaxBitsPerWrite;
|
||||
offset += gMaxBitsPerWrite;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,27 +490,38 @@ void ModbusWriteRegisters(word address, long count, word values[])
|
|||
byte dataLength;
|
||||
word overallLength;
|
||||
word i;
|
||||
long offset;
|
||||
|
||||
// FC16: Write Multiple Registers (AOs)
|
||||
offset = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
curCount = count > gMaxRegsPerWrite ? gMaxRegsPerWrite : count;
|
||||
dataLength = 2 * curCount;
|
||||
overallLength = maxLength - 2*gMaxRegsPerWrite + dataLength;
|
||||
|
||||
if (curCount == 1)
|
||||
{
|
||||
ModbusWriteRegister(address, values[offset]);
|
||||
return;
|
||||
}
|
||||
|
||||
_ModbusMakeHeader(mbreq.Header, overallLength, funcCode);
|
||||
|
||||
mbreq.Address = address; // [2] Output address
|
||||
mbreq.Address = address+offset; // [2] Output address
|
||||
mbreq.Count = curCount; // [2] Number of items; 1:max 123=0x7B
|
||||
mbreq.ByteCount = dataLength; // [1] Number of bytes; = 2 * count
|
||||
|
||||
for (i = 0; i < curCount; i++)
|
||||
mbreq.Data[i] = values[i];
|
||||
mbreq.Data[i] = values[i+offset];
|
||||
for ( ; i < gMaxRegsPerWrite; i++) // do we need this?
|
||||
mbreq.Data[i] = 0;
|
||||
|
||||
memcpy_h2n(buffer, mbreq);
|
||||
_ModbusSend(buffer, overallLength, mbreq.Header.TxID);
|
||||
|
||||
count -= gMaxRegsPerWrite;
|
||||
offset += gMaxRegsPerWrite;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,7 +773,7 @@ void _OnModbusReceive2OnePacket(byte buffer[], int offset, struct ModbusApHeader
|
|||
if (mbap.FuncCode > 0x80) // Oh no, we got a exception!
|
||||
_OnModbusReceive2Exceptions(buffer[offset+08], mbap);
|
||||
else // Ok, everything is alright
|
||||
_OnModbusReceive2Success(buffer, mbap);
|
||||
_OnModbusReceive2Success(buffer, mbap, offset, length);
|
||||
|
||||
gQueueAck.Remove(mbap.TxID); // Remove from acknowledge queue
|
||||
}
|
||||
|
@ -797,7 +820,7 @@ void _OnModbusReceive2Exceptions(byte exCode, struct ModbusApHeader mbap)
|
|||
/// <-OnModbusReceive>
|
||||
// This method will hand the received data to the correct Success() function
|
||||
// It gets called by _OnModbusReceive2OnePacket()
|
||||
void _OnModbusReceive2Success(byte exCode, struct ModbusApHeader mbap)
|
||||
void _OnModbusReceive2Success(byte buffer[], struct ModbusApHeader mbap, int offset, word length)
|
||||
{
|
||||
byte mbuffer[gModbusMaxTelegramSize]; // second buffer where we copy the message. This way the user won't overwrite other packages.
|
||||
// Copy the message
|
||||
|
@ -880,25 +903,25 @@ on timer gtModbusRobin
|
|||
// First: check timeouts = packets that were sent in previous run and not removed by response
|
||||
for (long TxID : gQueueSent)
|
||||
{
|
||||
if (++gQueueSent[TxID].TimeoutTicks < @sysvar::Config::Modbus::RequestTimeout) // not timed out yet
|
||||
if (++gQueueSent[TxID].TimeoutTicks < gRequestTimeout) // not timed out yet
|
||||
continue;
|
||||
// timed out!
|
||||
if (++gQueueSent[TxID].Timeouts < @sysvar::Config::Modbus::MaxTransmissionCount) // if we may resend it
|
||||
// timed out!
|
||||
if (++gQueueSent[TxID].Timeouts < gMaxTransmissionCount) // if we may resend it
|
||||
{
|
||||
writeDbg(ConnInfo, "Packet 0x%04X timed out! Retrying...", TxID);
|
||||
gQueueSent[TxID].TimeoutTicks = 0;
|
||||
_ModbusSnd(gQueueSent[TxID].Buffer, gQueueSent[TxID].Length); // resend it
|
||||
_ModbusSnd(gQueueSent[TxID].Buffer, gQueueSent[TxID].Length); // resend it
|
||||
reqError = Timeout;
|
||||
_ModbusRecv();
|
||||
}
|
||||
else // we will NOT resend it
|
||||
else // we will NOT resend it
|
||||
{
|
||||
writeDbg(ConnWarning, "Packet 0x%04X timed out! Giving up", TxID);
|
||||
reqError = FinalTimeout;
|
||||
}
|
||||
|
||||
memcpy_n2h(mbap, gQueueSent[TxID].Buffer);
|
||||
switch(mbap.FuncCode) // throw an "error" in each case
|
||||
switch(mbap.FuncCode) // throw an "error" in each case
|
||||
{
|
||||
case ReadBits1:
|
||||
case ReadBits2:
|
||||
|
|
Loading…
Reference in a new issue