ModbusClient.cin
Counting the send attempts to reject packets that cannot be send (e.g. wrong network) MakeConfig.can Introduced options (skip255 and useThirdIpNameForNodeName)
This commit is contained in:
parent
caf58bd7d6
commit
84ab39d5b3
6 changed files with 127 additions and 66 deletions
|
@ -1,4 +1,4 @@
|
|||
;CANoe Version |4|7|1|52132 MakeConfig
|
||||
;CANoe Version |4|7|1|52133 MakeConfig
|
||||
Version: 8.2.40 Build 40
|
||||
32 PRO
|
||||
5
|
||||
|
@ -1261,9 +1261,37 @@ Grafik-Fenster
|
|||
237
|
||||
0
|
||||
0
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
-11
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
400
|
||||
0
|
||||
Tahoma
|
||||
0
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
-11
|
||||
0
|
||||
0
|
||||
0
|
||||
34
|
||||
0
|
||||
0
|
||||
0
|
||||
400
|
||||
0
|
||||
Tahoma
|
||||
0
|
||||
1
|
||||
1
|
||||
|
@ -2933,7 +2961,7 @@ End_Of_Object VGrMnBox 3
|
|||
VDOLocalInfoStruct 3 Begin_Of_Object
|
||||
3
|
||||
1
|
||||
98
|
||||
101
|
||||
VDAOBus 4 Begin_Of_Object
|
||||
1
|
||||
1
|
||||
|
@ -3063,7 +3091,7 @@ VSimulinkModelViewerConfiguration 7 Begin_Of_Object
|
|||
End_Of_Object VSimulinkModelViewerConfiguration 7
|
||||
1
|
||||
0
|
||||
4212996857
|
||||
1115474418
|
||||
0
|
||||
NodeSignalPanelBustypeCount 0
|
||||
End_Of_Object VSimulationNode 6
|
||||
|
@ -3101,7 +3129,7 @@ NULL
|
|||
End_Of_Object VDOLocalInfoStruct 3
|
||||
0.000000
|
||||
0 0
|
||||
1 1 0 59420 1 233 1 2882400001 98 331 371 619 2882400002 0 0 0 0 0 0 1 2882400001 1270 1270 373 373 2882400002 0 0 0 335238400 0 336542644 3
|
||||
1 1 0 59420 1 233 1 2882400001 98 331 371 619 2882400002 0 0 0 0 0 0 1 2882400001 1270 1270 373 373 2882400002 0 0 0 355173376 0 423022796 3
|
||||
SS_BEGIN_COMMON_INFO
|
||||
1
|
||||
0
|
||||
|
@ -3113,7 +3141,7 @@ Ethernet
|
|||
11
|
||||
1
|
||||
1
|
||||
335879144 1 0 1 0 0 1 0 0 0 2000 1
|
||||
422945832 1 0 1 0 0 1 0 0 0 2000 1
|
||||
SS_BEGIN_COMMON_INFO
|
||||
1
|
||||
3
|
||||
|
@ -3224,7 +3252,7 @@ End_Of_Serialized_Data 2
|
|||
End_Of_Object VWriteBox 2
|
||||
VWinStore 2 Begin_Of_Object
|
||||
1
|
||||
22 2 3 -1 -1 -1 -1 -10088 -10000 -9070 -9233
|
||||
22 2 3 -32088 -32000 -1 -1 -10088 -10000 -9070 -9233
|
||||
End_Of_Child_List
|
||||
End_Of_Object VWinStore 2
|
||||
VWinStore 2 Begin_Of_Object
|
||||
|
@ -3537,6 +3565,7 @@ End
|
|||
FiltersEnd
|
||||
0 0
|
||||
|
||||
|
||||
END_OF_WORKSPACE_MEMBER_DATA
|
||||
END_OF_WORKSPACE_MEMBER
|
||||
1
|
||||
|
|
|
@ -25,6 +25,8 @@ variables
|
|||
word ADi, ADn, ADl; // Some variables for "AnalyzeDevices"
|
||||
|
||||
byte ggMaxTransmissionCount;
|
||||
byte useThirdIpByteForNames; // Whether the third byte of the IP address shall be used in the node name
|
||||
byte skip255; // Whether the IP address .255 (broadcast in /24) shall be skipped
|
||||
}
|
||||
|
||||
on preStart
|
||||
|
@ -39,7 +41,12 @@ on preStart
|
|||
// Scan a range of IPs for devices (if nothing was set above). Start and Stop go here
|
||||
// Please note: Currently .255 will be skipped! Don't use this address for devices
|
||||
strncpy(gScanFirstIp, "192.168.1.2", elCount(gScanFirstIp));
|
||||
strncpy(gScanLastIp, "192.168.1.20", elCount(gScanLastIp));
|
||||
strncpy(gScanLastIp, "192.168.2.20", elCount(gScanLastIp));
|
||||
|
||||
// Whether the third byte of the IP address shall be used in the node name
|
||||
useThirdIpByteForNames = 0;
|
||||
// Whether the IP address .255 (broadcast in /24) shall be skipped
|
||||
skip255 = 1;
|
||||
|
||||
// Name of the project
|
||||
strncpy(name, "Modbus", elCount(name));
|
||||
|
@ -48,7 +55,7 @@ on preStart
|
|||
strncpy(fnSysvar, "include/SysVars/generated.vsysvar", elCount(fnSysvar));
|
||||
strncpy(fnDbc, "include/DBC/generated.dbc", elCount(fnDbc));
|
||||
|
||||
OutputDebugLevel = Debug;//Error;
|
||||
OutputDebugLevel = Error;
|
||||
}
|
||||
|
||||
on start
|
||||
|
@ -87,7 +94,7 @@ void PutString(byte d)
|
|||
/// <Step1>
|
||||
void DetectDevices()
|
||||
{
|
||||
write("Scanning from %s to %s with timeout of %d ms", gScanFirstIp, gScanLastIp, @sysvar::Config::Modbus::RequestTimeout);
|
||||
writeLineEx(0, 1, "Scanning from %s to %s with timeout of %d ms", gScanFirstIp, gScanLastIp, @sysvar::Config::Modbus::RequestTimeout);
|
||||
|
||||
gScanFirst = ipGetAddressAsNumber(gScanFirstIp); // We have to use big endian here
|
||||
gScanLast = swapDWord(ipGetAddressAsNumber(gScanLastIp)); // But not here :)
|
||||
|
@ -102,11 +109,15 @@ void DetectDevicesNext()
|
|||
{
|
||||
gScanFirst = swapDWord(gScanFirst);
|
||||
gScanFirst++;
|
||||
if ((gScanFirst & 0xFF) == 0xFF) // skip .255
|
||||
if (skip255 && (gScanFirst & 0xFF) == 0xFF) // skip .255
|
||||
{
|
||||
gScanFirst++;
|
||||
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF);
|
||||
}
|
||||
else if (!skip255 && (gScanFirst & 0xFF) == 0x00)
|
||||
{
|
||||
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF);
|
||||
}
|
||||
|
||||
if (gScanFirst > gScanLast)
|
||||
{
|
||||
|
@ -124,12 +135,7 @@ void DetectDevicesNext()
|
|||
/// <Step1>
|
||||
void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case FinalTimeout:
|
||||
case Exception:
|
||||
DetectDevicesNext(); // Timeout! We will go to the next device
|
||||
}
|
||||
DetectDevicesNext(); // Timeout, NotSent, Exception! We will go to the next device
|
||||
}
|
||||
/// <Step1>
|
||||
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq)
|
||||
|
@ -238,6 +244,9 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
|
|||
case FinalTimeout:
|
||||
writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP);
|
||||
break;
|
||||
case NotSent:
|
||||
writeLineEx(0, 3, "Error while analyzing %s! The device was not available! Ignoring...", gIpsSorted[ips[ADi]].IP);
|
||||
break;
|
||||
}
|
||||
gQueueAck.Clear(); // Clear all queues
|
||||
gQueuePending.Clear();
|
||||
|
@ -317,8 +326,11 @@ void GenSysvars()
|
|||
DeviceInit(gIpsSorted[ipN].Vendor);
|
||||
|
||||
PutString(" <namespace name=\"Client_");
|
||||
//PutString(netS);
|
||||
//PutString("_");
|
||||
if (useThirdIpByteForNames)
|
||||
{
|
||||
PutString(gIpsSorted[ipN].IpNet);
|
||||
PutString("_");
|
||||
}
|
||||
PutString(gIpsSorted[ipN].IpLsb);
|
||||
PutString("\" comment=\"Server with ip address '");
|
||||
PutString(gIpsSorted[ipN].Ip);
|
||||
|
@ -466,8 +478,11 @@ void GenDbc()
|
|||
for (long ipN : gIpsSorted)
|
||||
{
|
||||
PutString(" Client_");
|
||||
//PutString(gIpsSorted[ipN].IpNet);
|
||||
//PutString("_");
|
||||
if (useThirdIpByteForNames)
|
||||
{
|
||||
PutString(gIpsSorted[ipN].IpNet);
|
||||
PutString("_");
|
||||
}
|
||||
PutString(gIpsSorted[ipN].IpLsb);
|
||||
}
|
||||
PutString("\n\n\n\n");
|
||||
|
|
|
@ -38,7 +38,7 @@ variables
|
|||
|
||||
enum Vendor // The Vendor enum. All Vendors have to listed here and all listed vendors have to be implemented in this file
|
||||
{
|
||||
All = 0xFFFF,
|
||||
All = 0xFF,
|
||||
Wago = 23, // Wago
|
||||
BuR = 2 // B&R
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@ variables
|
|||
{
|
||||
word TimeoutTicks; // Time counter [ms]. Used to watch for timeouts (see gRequestTimeout)
|
||||
byte Timeouts;
|
||||
byte SendTries;
|
||||
word Length;
|
||||
byte Buffer[gModbusMaxTelegramSize];
|
||||
};
|
||||
|
@ -157,6 +158,7 @@ void _ModbusReadBits(enum ModbusFuncCode funcCode, word address, long count)
|
|||
OnModbusClientPanics(AddressFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// FC1: Read Coils (DO), FC2: Read Discret Inputs (DI)
|
||||
while (count > 0 && address < devEndAddr)
|
||||
{
|
||||
|
@ -279,7 +281,7 @@ void _ModbusReadRegisters(enum ModbusFuncCode funcCode, word address, long count
|
|||
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);
|
||||
//write("address = 0x%04X, count = %d, curCount = %d, devStartAddr = 0x%04X, devEndAddr = 0x%04X", address, count, curCount, devStartAddr, devEndAddr);
|
||||
|
||||
_ModbusMakeHeader(mbreq.Header, length, funcCode);
|
||||
|
||||
|
@ -440,6 +442,7 @@ void ModbusWriteBits(word address, long count, byte values[])
|
|||
long offset;
|
||||
|
||||
// FC15: Write Multiple Bits (DOs)
|
||||
offset = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
if (count > gMaxBitsPerWrite)
|
||||
|
@ -463,7 +466,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. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address, curCount);
|
||||
writeDbg(MbDebug, "Sending 'Write Bits' (0x0F) command. TxID: 0x%04X, Addr: 0x%04X, Count: %d", mbreq.Header.TxID, address+offset, curCount);
|
||||
|
||||
memcpy_h2n(buffer, mbreq);
|
||||
_ModbusSend(buffer, overallLength, mbreq.Header.TxID);
|
||||
|
@ -955,7 +958,6 @@ void _ModbusStartQueue()
|
|||
// The pending packets may be sent when there is free space in the sending window
|
||||
on timer gtModbusRobin
|
||||
{
|
||||
struct ModbusApHeader mbap;
|
||||
enum ModbusRequestError reqError;
|
||||
|
||||
writeDbg(ConnDebug, "gtModbusRobin: Queue Sent: %d, Queue Pending: %d, Queue Ack: %d", gQueueSent.Size(), gQueuePending.Size(), gQueueAck.Size());
|
||||
|
@ -968,7 +970,7 @@ on timer gtModbusRobin
|
|||
// timed out!
|
||||
if (++gQueueSent[TxID].Timeouts < gMaxTransmissionCount) // if we may resend it
|
||||
{
|
||||
writeDbg(ConnInfo, "Packet 0x%04X timed out! Retrying...", TxID);
|
||||
writeDbg(ConnInfo, "gtModbusRobin: Packet 0x%04X timed out! Retrying...", TxID);
|
||||
gQueueSent[TxID].TimeoutTicks = 0;
|
||||
_ModbusSnd(gQueueSent[TxID].Buffer, gQueueSent[TxID].Length); // resend it
|
||||
reqError = Timeout;
|
||||
|
@ -976,43 +978,14 @@ on timer gtModbusRobin
|
|||
}
|
||||
else // we will NOT resend it
|
||||
{
|
||||
writeDbg(ConnWarning, "Packet 0x%04X timed out! Giving up", TxID);
|
||||
writeDbg(ConnWarning, "gtModbusRobin: 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
|
||||
{
|
||||
case ReadBitsOut:
|
||||
case ReadBitsIn:
|
||||
OnModbusReadBitsFailed(reqError, None, mbap);
|
||||
break;
|
||||
case ReadRegistersOut:
|
||||
case ReadRegistersIn:
|
||||
OnModbusReadRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteBit:
|
||||
OnModbusWriteBitFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteRegister:
|
||||
OnModbusWriteRegisterFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteBits:
|
||||
OnModbusWriteBitsFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteRegisters:
|
||||
OnModbusWriteRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
case MaskRegister:
|
||||
OnModbusWriteMasksFailed(reqError, None, mbap);
|
||||
break;
|
||||
case ReadWriteRegisters:
|
||||
OnModbusReadWriteRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reqError == FinalTimeout) // remove the packet from queue
|
||||
gQueueSent.Remove(TxID); // wait until here to let the methods above access the request
|
||||
_ModbusSendTimerError(gQueueSent[TxID].Buffer, reqError); // throw an "error" in each case
|
||||
|
||||
if (reqError == FinalTimeout) // remove the packet from queue
|
||||
gQueueSent.Remove(TxID); // wait until here to let the methods above access the request
|
||||
}
|
||||
|
||||
// Second: send new packets
|
||||
|
@ -1025,16 +998,59 @@ on timer gtModbusRobin
|
|||
// if packet was sent or the socket is not currently being opened
|
||||
if (_ModbusSnd(gQueuePending[TxID].Buffer, gQueuePending[TxID].Length) == 0)
|
||||
{
|
||||
memcpy(gQueueSent[TxID], gQueuePending[TxID]); // move packet to sent queue
|
||||
memcpy(gQueueSent[TxID], gQueuePending[TxID]); // move packet to sent queue
|
||||
gQueuePending.Remove(TxID);
|
||||
_ModbusRecv(); // wait for new packets
|
||||
}
|
||||
else if (gQueuePending[TxID].SendTries++ > 10) // We have tried to send this packet too often. Something is wrong!?
|
||||
{
|
||||
writeDbg(ConnError, "gtModbusRobin: The packet 0x%04X could not be sent, _ModbusSnd() rejected it several times", TxID);
|
||||
_ModbusSendTimerError(gQueuePending[TxID].Buffer, NotSent);
|
||||
gQueuePending.Remove(TxID);
|
||||
_ModbusRecv(); // wait for new packets
|
||||
}
|
||||
}
|
||||
|
||||
// Stop timer to reduce load and latency of first new packet
|
||||
if (gSocketState == ERROR || gQueueSent.Size() == 0 && gQueuePending.Size() == 0)
|
||||
{
|
||||
writeDbg(ConnDebug, "Stopping Timer gtModbusRobin");
|
||||
writeDbg(ConnDebug, "gtModbusRobin: Stopping Timer");
|
||||
this.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/// <-ModbusSend>
|
||||
// This method will give an Error
|
||||
void _ModbusSendTimerError(byte buffer[], enum ModbusRequestError reqError)
|
||||
{
|
||||
struct ModbusApHeader mbap;
|
||||
memcpy_n2h(mbap, buffer);
|
||||
switch(mbap.FuncCode)
|
||||
{
|
||||
case ReadBitsOut:
|
||||
case ReadBitsIn:
|
||||
OnModbusReadBitsFailed(reqError, None, mbap);
|
||||
break;
|
||||
case ReadRegistersOut:
|
||||
case ReadRegistersIn:
|
||||
OnModbusReadRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteBit:
|
||||
OnModbusWriteBitFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteRegister:
|
||||
OnModbusWriteRegisterFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteBits:
|
||||
OnModbusWriteBitsFailed(reqError, None, mbap);
|
||||
break;
|
||||
case WriteRegisters:
|
||||
OnModbusWriteRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
case MaskRegister:
|
||||
OnModbusWriteMasksFailed(reqError, None, mbap);
|
||||
break;
|
||||
case ReadWriteRegisters:
|
||||
OnModbusReadWriteRegistersFailed(reqError, None, mbap);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ variables
|
|||
word Protocol;
|
||||
word Length;
|
||||
byte UnitID;
|
||||
/*enum ModbusFuncCode*/ byte FuncCode;
|
||||
byte FuncCode;
|
||||
};
|
||||
// Read Data from the host. We only need the start address and the number of bits/registers we want to read
|
||||
_align(1) struct ModbusReqRead
|
||||
|
@ -95,7 +95,7 @@ variables
|
|||
{
|
||||
struct ModbusApHeader Header;
|
||||
byte ByteCount;
|
||||
word Data[gMaxRegsPerRead]; // Max length: 125 registers
|
||||
word Data[gMaxRegsPerRead]; // Max length: 125 registers
|
||||
};
|
||||
// Confirm the write of a single bit/register
|
||||
_align(1) struct ModbusResConfirmSingle
|
||||
|
@ -127,7 +127,8 @@ variables
|
|||
{
|
||||
Exception,
|
||||
Timeout,
|
||||
FinalTimeout
|
||||
FinalTimeout,
|
||||
NotSent
|
||||
};
|
||||
enum ModbusException
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ NS_ :
|
|||
|
||||
BS_:
|
||||
|
||||
BU_: Client_ Client_100 Client_101
|
||||
BU_: Client_2 Client_3
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue