Moved all sysvars to PollingModbusClient.can

Fixed bug when splitting Modbus write requests
This commit is contained in:
Jonny007-MKD 2014-07-04 11:29:18 +00:00
parent b6f211d5d3
commit 2df8f31eb7
2 changed files with 40 additions and 17 deletions

View file

@ -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

View file

@ -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: