Rename generated.dbc and generated.vsysvar into Modbus.*
DeviceInformation.cin struct device now contains all 4 bytes of the IP as fields MakeConfig.can Improved code and comments MakeConfig.can PollingModbusClient.can Removed the subnetting stuff. We simply can add the net to the node name
This commit is contained in:
parent
c181aa857b
commit
eb6d28c71b
7 changed files with 228 additions and 223 deletions
|
@ -1,14 +1,4 @@
|
||||||
/*@!Encoding:1252*/
|
/*@!Encoding:1252*/
|
||||||
includes
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
variables
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
on sysvar sysvar::Airbus::ESS_DC1
|
on sysvar sysvar::Airbus::ESS_DC1
|
||||||
{
|
{
|
||||||
if (@this)
|
if (@this)
|
||||||
|
|
|
@ -8,25 +8,25 @@ includes
|
||||||
|
|
||||||
variables
|
variables
|
||||||
{
|
{
|
||||||
char[16] gIps[long]; // List IP addresses. These will be analysed
|
char[16] gIps[long]; // List of IP addresses. These will be analysed
|
||||||
char gScanFirstIp[16]; // The first IP address that will be scanned
|
char gScanFirstIp[16]; // The first IP address that will be scanned
|
||||||
char gScanLastIp[16]; // The first IP address that will not be scanned anymore.
|
char gScanLastIp[16]; // The first IP address that will be scanned
|
||||||
|
byte skip255; // Whether the IP address .255 (broadcast in /24 nets) shall be skipped
|
||||||
|
|
||||||
char fnSysvar[40]; // Filename of Sysvars
|
char fnSysvar[100]; // Filename of Sysvars
|
||||||
char fnDbc[40]; // Filename of DBC
|
char fnDbc[100]; // Filename of DBC
|
||||||
char name[20]; // Name of project (not important)
|
dword ips[50]; // detected IPs. We need this array for enumeration with integers (assoc. arrays cannot be enumerated with integers :( )
|
||||||
dword ips[50]; // detected IPs. We need this array for enumeration with integers
|
|
||||||
|
|
||||||
|
|
||||||
file f; // The file we are writing to
|
file f; // The file we are writing to
|
||||||
byte gIpNets[long]; // A list of nets
|
|
||||||
struct device gIpsSorted[long]; // The final array with the devices
|
struct device gIpsSorted[long]; // The final array with the devices
|
||||||
dword gScanFirst, gScanLast; // The first and last IP address as dword
|
dword gScanCurr, gScanLast; // The first and last IP address as dword
|
||||||
word ADi, ADn, ADl; // Some variables for "AnalyzeDevices"
|
word ADi, ADn, ADl; // Some variables for AnalyzeDevices() (event driven, so global)
|
||||||
|
|
||||||
byte ggMaxTransmissionCount;
|
byte ggMaxTransmissionCount; // temp var for gMaxTransmissionCount
|
||||||
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
|
enum eNodeName {WholeIP, LastByte, TwoLastBytes, ThreeLastBytes}
|
||||||
|
enum eNodeName NodeNameStyle; // The style of the node name
|
||||||
}
|
}
|
||||||
|
|
||||||
on preStart
|
on preStart
|
||||||
|
@ -35,25 +35,23 @@ on preStart
|
||||||
// List of IPs of devices goes here
|
// List of IPs of devices goes here
|
||||||
///strncpy(gIps[i++], "192.168.1.100", elCount(gIps));
|
///strncpy(gIps[i++], "192.168.1.100", elCount(gIps));
|
||||||
///strncpy(gIps[i++], "192.168.1.101", elCount(gIps));
|
///strncpy(gIps[i++], "192.168.1.101", elCount(gIps));
|
||||||
///strncpy(gIps[i++], "192.168.100.2", elCount(gIps));
|
|
||||||
///strncpy(gIps[i++], "192.168.1.8", elCount(gIps));
|
|
||||||
|
|
||||||
// Scan a range of IPs for devices (if nothing was set above). Start and Stop go here
|
// 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(gScanFirstIp, "192.168.1.2", elCount(gScanFirstIp));
|
||||||
strncpy(gScanLastIp, "192.168.1.255", elCount(gScanLastIp));
|
strncpy(gScanLastIp, "192.168.1.255", elCount(gScanLastIp));
|
||||||
|
|
||||||
// Whether the third byte of the IP address shall be used in the node name
|
// How the Node name shall be formatted
|
||||||
useThirdIpByteForNames = 0;
|
// LastByte: 192.168.12.34 --> Client_34
|
||||||
|
// TwoLastBytes: 192.168.12.34 --> Client_12_34
|
||||||
|
// ThreeLastBytes: 192.168.12.34 --> Client_168_12_34
|
||||||
|
// WholeIp: 192.168.12.34 --> Client_192_168_12_34
|
||||||
|
NodeNameStyle = LastByte;
|
||||||
// Whether the IP address .255 (broadcast in /24) shall be skipped
|
// Whether the IP address .255 (broadcast in /24) shall be skipped
|
||||||
skip255 = 1;
|
skip255 = 1;
|
||||||
|
|
||||||
// Name of the project
|
|
||||||
strncpy(name, "Modbus", elCount(name));
|
|
||||||
|
|
||||||
// Paths to the generated files relative to MakeConfig.cfg
|
// Paths to the generated files relative to MakeConfig.cfg
|
||||||
strncpy(fnSysvar, "include/SysVars/generated.vsysvar", elCount(fnSysvar));
|
strncpy(fnSysvar, "include/SysVars/Modbus.vsysvar", elCount(fnSysvar));
|
||||||
strncpy(fnDbc, "include/DBC/generated.dbc", elCount(fnDbc));
|
strncpy(fnDbc, "include/DBC/Modbus.dbc", elCount(fnDbc));
|
||||||
|
|
||||||
OutputDebugLevel = Error;
|
OutputDebugLevel = Error;
|
||||||
}
|
}
|
||||||
|
@ -96,10 +94,10 @@ void DetectDevices()
|
||||||
{
|
{
|
||||||
writeLineEx(0, 1, "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
|
gScanCurr = ipGetAddressAsNumber(gScanFirstIp); // We have to use big endian here
|
||||||
gScanLast = swapDWord(ipGetAddressAsNumber(gScanLastIp)); // But not here :)
|
gScanLast = swapDWord(ipGetAddressAsNumber(gScanLastIp)); // But not here :)
|
||||||
|
|
||||||
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24);
|
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanCurr & 0xFF, (gScanCurr >> 8) & 0xFF, (gScanCurr >> 16) & 0xFF, gScanCurr >> 24);
|
||||||
ModbusInit(gScanFirstIp, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, 1); // Open socket and set variables
|
ModbusInit(gScanFirstIp, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, 1); // Open socket and set variables
|
||||||
ModbusReadBits(0, 1); // Start device detection
|
ModbusReadBits(0, 1); // Start device detection
|
||||||
}
|
}
|
||||||
|
@ -107,46 +105,43 @@ void DetectDevices()
|
||||||
/// <Step1>
|
/// <Step1>
|
||||||
void DetectDevicesNext()
|
void DetectDevicesNext()
|
||||||
{
|
{
|
||||||
gScanFirst = swapDWord(gScanFirst);
|
gScanCurr = swapDWord(gScanCurr); // Swap to increment
|
||||||
gScanFirst++;
|
gScanCurr++; // Increment
|
||||||
if (skip255 && (gScanFirst & 0xFF) == 0xFF) // skip .255
|
if ((gScanCurr & 0xFF) == 0xFF) // If .255
|
||||||
{
|
{
|
||||||
gScanFirst++;
|
if (skip255) // If we shall skip .255
|
||||||
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF);
|
gScanCurr++;
|
||||||
}
|
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanCurr >> 24, (gScanCurr >> 16) & 0xFF, (gScanCurr >> 8) & 0xFF, gScanCurr & 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)
|
if (gScanCurr > gScanLast) // If we are beyond the last ip address
|
||||||
{
|
{
|
||||||
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount;
|
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount; // reset
|
||||||
MakeIpNets();
|
MakeIpNets(); // Continue with Step 2
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gScanFirst = swapDWord(gScanFirst);
|
gScanCurr = swapDWord(gScanCurr); // Swap back
|
||||||
|
|
||||||
writeEx(0, 0, "."); // Write something so the user knows something is happening
|
writeEx(0, 0, "."); // Write something so the user knows something is happening
|
||||||
gRemoteIP = gScanFirst; // Don't open new socket, it takes too much time. This means we should use UDP here!
|
gRemoteIP = gScanCurr; // Don't open new socket, it takes too much time. This means we should use UDP or EIL here!
|
||||||
ModbusReadBits(0, 1); // Scan the next device
|
ModbusReadBits(0, 1); // Scan the next device
|
||||||
}
|
}
|
||||||
/// <Step1>
|
/// <Step1>
|
||||||
void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
|
void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
|
||||||
{
|
{
|
||||||
DetectDevicesNext(); // Timeout, NotSent, Exception! We will go to the next device
|
DetectDevicesNext(); // Timeout, NotSent or Exception! We will go to the next device
|
||||||
}
|
}
|
||||||
/// <Step1>
|
/// <Step1>
|
||||||
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq)
|
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq)
|
||||||
{
|
{
|
||||||
ipGetAddressAsString(gScanFirst, gIps[gScanFirst], 16); // store the detected device's IP address
|
ipGetAddressAsString(gScanCurr, gIps[gScanCurr], 16); // store the detected device's IP address
|
||||||
DetectDevicesNext(); // and continue
|
DetectDevicesNext(); // and continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Step 2: Sort into subnets and create structure
|
// Step 2: Sort into subnets and create structure
|
||||||
// Sort the IPs from gIps to gIpsSorted and add their subnet to gIpNets
|
// Sort the IPs from gIps to gIpsSorted
|
||||||
/// <Step2>
|
/// <Step2>
|
||||||
void MakeIpNets()
|
void MakeIpNets()
|
||||||
{
|
{
|
||||||
|
@ -159,16 +154,17 @@ void MakeIpNets()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long i : gIps) // Go through all devices
|
for (long i : gIps) // Iterate all devices
|
||||||
{
|
{
|
||||||
ipNum = ipGetAddressAsNumber(gIps[i]); // convert IP to dword
|
ipNum = ipGetAddressAsNumber(gIps[i]); // convert IP to dword
|
||||||
|
|
||||||
gIpNets[(ipNum >> 16) & 0xFF] = 1; // register subnet
|
|
||||||
ips[gIpsSorted.size()] = ipNum; // add ip address to normal array
|
ips[gIpsSorted.size()] = ipNum; // add ip address to normal array
|
||||||
// fill the device structure array:
|
// fill the device structure array:
|
||||||
strncpy(gIpsSorted[ipNum].IP, gIps[i], 16); // set .IP
|
strncpy(gIpsSorted[ipNum].IP, gIps[i], 16); // set .IP
|
||||||
ltoa((ipNum >> 16) & 0xFF, gIpsSorted[ipNum].IpNet, 10); // set .IpNet
|
ltoa((ipNum ) & 0xFF, gIpsSorted[ipNum].Ip1, 10); // set .Ip1
|
||||||
ltoa((ipNum >> 24) & 0xFF, gIpsSorted[ipNum].IpLsb, 10); // set .IpLsb
|
ltoa((ipNum >> 8) & 0xFF, gIpsSorted[ipNum].Ip2, 10); // set .Ip2
|
||||||
|
ltoa((ipNum >> 16) & 0xFF, gIpsSorted[ipNum].Ip3, 10); // set .Ip3
|
||||||
|
ltoa((ipNum >> 24) & 0xFF, gIpsSorted[ipNum].Ip4, 10); // set .Ip4
|
||||||
|
|
||||||
gIps.Remove(i);
|
gIps.Remove(i);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +178,7 @@ void MakeIpNets()
|
||||||
void AnalyzeDevices()
|
void AnalyzeDevices()
|
||||||
{
|
{
|
||||||
// Init counters
|
// Init counters
|
||||||
ADn = 1; // expect 10 responses
|
ADn = 1; // expect 1 response
|
||||||
ADi = 0; // First IP address
|
ADi = 0; // First IP address
|
||||||
ADl = gIpsSorted.Size();
|
ADl = gIpsSorted.Size();
|
||||||
|
|
||||||
|
@ -203,17 +199,19 @@ void AnalyzeDevices()
|
||||||
/// <Step3>
|
/// <Step3>
|
||||||
void AnalyzeDevicesNext()
|
void AnalyzeDevicesNext()
|
||||||
{
|
{
|
||||||
if (strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules) > 0)
|
// clean up the string of the previous devices
|
||||||
gIpsSorted[ips[ADi]].DeviceIOs.Modules[strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules)-1] = 0;
|
if (strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules) > 0) // If we do have some Modules in this string
|
||||||
|
gIpsSorted[ips[ADi]].DeviceIOs.Modules[strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules)-1] = 0; // Remove the last comma (set the char to NUL)
|
||||||
|
// print the result
|
||||||
writeEx(0, 1, ": AOs: %d, AIs: %d, DOs: %d, DIs: %d --> %s", gIpsSorted[ips[ADi]].DeviceIOs.OutputRegisters, gIpsSorted[ips[ADi]].DeviceIOs.InputRegisters, gIpsSorted[ips[ADi]].DeviceIOs.OutputBits, gIpsSorted[ips[ADi]].DeviceIOs.InputBits, gIpsSorted[ips[ADi]].DeviceIOs.Modules);
|
writeEx(0, 1, ": AOs: %d, AIs: %d, DOs: %d, DIs: %d --> %s", gIpsSorted[ips[ADi]].DeviceIOs.OutputRegisters, gIpsSorted[ips[ADi]].DeviceIOs.InputRegisters, gIpsSorted[ips[ADi]].DeviceIOs.OutputBits, gIpsSorted[ips[ADi]].DeviceIOs.InputBits, gIpsSorted[ips[ADi]].DeviceIOs.Modules);
|
||||||
|
|
||||||
if (++ADi >= ADl) // we have analyzed all devices
|
if (++ADi >= ADl) // continue with the next device. If we have analyzed all devices
|
||||||
{
|
{
|
||||||
MakeFiles(); // go to Step4
|
MakeFiles(); // go to Step4
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADn = 1; // expect 10 responses
|
ADn = 1; // expect 1 response again
|
||||||
gRemoteIP = ips[ADi]; // Next IP address
|
gRemoteIP = ips[ADi]; // Next IP address
|
||||||
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
|
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
|
||||||
// request something special to get the vendor
|
// request something special to get the vendor
|
||||||
|
@ -226,12 +224,10 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
|
||||||
|
|
||||||
switch (error)
|
switch (error)
|
||||||
{
|
{
|
||||||
case Timeout:
|
|
||||||
return;
|
|
||||||
case Exception:
|
case Exception:
|
||||||
memcpy_n2h(mbreq, gQueueAck[mbap.TxID].Buffer);
|
memcpy_n2h(mbreq, gQueueAck[mbap.TxID].Buffer);
|
||||||
|
|
||||||
if (mbreq.Address == 0x1000 && ex == IllegalDataAddress) // We requested Wago SerialCode and it didn't work --> Not Wago --> B&R. Not future proof
|
if (mbreq.Address == 0x1000 && ex == IllegalDataAddress) // We requested B&R MAC and it didn't work --> Not B&R --> Wago. Not future proof :(
|
||||||
{
|
{
|
||||||
gIpsSorted[ips[ADi]].Vendor = Wago;
|
gIpsSorted[ips[ADi]].Vendor = Wago;
|
||||||
// request information
|
// request information
|
||||||
|
@ -241,6 +237,8 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
|
||||||
|
|
||||||
writeLineEx(0, 3, "Error while analyzing %s! The device respond with exception code %d! Ignoring...", gIpsSorted[ips[ADi]].IP, ex);
|
writeLineEx(0, 3, "Error while analyzing %s! The device respond with exception code %d! Ignoring...", gIpsSorted[ips[ADi]].IP, ex);
|
||||||
break;
|
break;
|
||||||
|
case Timeout:
|
||||||
|
return; // Timeout is unimportant, it means the request will be resent
|
||||||
case FinalTimeout:
|
case FinalTimeout:
|
||||||
writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP);
|
writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP);
|
||||||
break;
|
break;
|
||||||
|
@ -261,7 +259,7 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
|
||||||
/// <Step3>
|
/// <Step3>
|
||||||
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq)
|
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq)
|
||||||
{
|
{
|
||||||
if (mbreq.Address == 0x1000) // We detected a B&R device
|
if (mbreq.Address == 0x1000) // We detected a B&R device (from MAC address)
|
||||||
{
|
{
|
||||||
gIpsSorted[ips[ADi]].Vendor = BuR;
|
gIpsSorted[ips[ADi]].Vendor = BuR;
|
||||||
|
|
||||||
|
@ -270,10 +268,11 @@ void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// else parse the received data
|
||||||
_DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count);
|
_DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count);
|
||||||
|
|
||||||
if (--ADn == 0) // If we received all registers
|
if (--ADn == 0) // If we received all registers
|
||||||
AnalyzeDevicesNext();
|
AnalyzeDevicesNext(); // Continue with the next device
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Create the files with the queried data
|
// Step 4: Create the files with the queried data
|
||||||
|
@ -313,29 +312,34 @@ void GenSysvars()
|
||||||
PutString(" </namespace>\n");
|
PutString(" </namespace>\n");
|
||||||
PutString(" </namespace>\n");
|
PutString(" </namespace>\n");
|
||||||
|
|
||||||
for (long net : gIpNets)
|
PutString(" <namespace name=\"Ethernet\" comment=\"\">\n");
|
||||||
{
|
|
||||||
byte nett;
|
|
||||||
nett = net;
|
|
||||||
PutString(" <namespace name=\"Ethernet");
|
|
||||||
PutString(nett);
|
|
||||||
PutString("\" comment=\"Subnet: 192.168.");
|
|
||||||
PutString(nett);
|
|
||||||
PutString(".\">\n");
|
|
||||||
|
|
||||||
for (long ipN : gIpsSorted)
|
for (long ipN : gIpsSorted)
|
||||||
{
|
{
|
||||||
if (((ipN >> 16) & 0xFF) != net)
|
if ((ipN >> 16) & 0xFF != net) // This IP does not belong to the current net
|
||||||
continue;
|
continue;
|
||||||
DeviceInit(gIpsSorted[ipN].Vendor);
|
DeviceInit(gIpsSorted[ipN].Vendor);
|
||||||
|
|
||||||
PutString(" <namespace name=\"Client_");
|
PutString(" <namespace name=\"Client_");
|
||||||
if (useThirdIpByteForNames)
|
switch (NodeNameStyle) // Add the IP bytes depending on the style. Don't break anywhere.
|
||||||
{
|
{
|
||||||
PutString(gIpsSorted[ipN].IpNet);
|
case WholeIp:
|
||||||
|
PutString(gIpsSorted[ipN].Ip1);
|
||||||
PutString("_");
|
PutString("_");
|
||||||
|
case ThreeLastBytes:
|
||||||
|
PutString(gIpsSorted[ipN].Ip2);
|
||||||
|
PutString("_");
|
||||||
|
case TwoLastBytes:
|
||||||
|
PutString(gIpsSorted[ipN].Ip3);
|
||||||
|
PutString("_");
|
||||||
|
case LastByte:
|
||||||
|
PutString(gIpsSorted[ipN].Ip4);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
writeDbg(MbError, "The NodeNameStyle %d is unknown, please use a value of the enum!", NodeNameStyle);
|
||||||
|
runError(1001, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
PutString(gIpsSorted[ipN].IpLsb);
|
|
||||||
PutString("\" comment=\"Server with ip address '");
|
PutString("\" comment=\"Server with ip address '");
|
||||||
PutString(gIpsSorted[ipN].Ip);
|
PutString(gIpsSorted[ipN].Ip);
|
||||||
PutString("'\">\n");
|
PutString("'\">\n");
|
||||||
|
@ -429,8 +433,6 @@ void GenSysvars()
|
||||||
PutString(" </namespace>\n");
|
PutString(" </namespace>\n");
|
||||||
PutString(" </namespace>\n");
|
PutString(" </namespace>\n");
|
||||||
}
|
}
|
||||||
PutString(" </namespace>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
PutString(" </namespace>\n");
|
PutString(" </namespace>\n");
|
||||||
PutString("</systemvariables>\n");
|
PutString("</systemvariables>\n");
|
||||||
|
@ -482,12 +484,25 @@ void GenDbc()
|
||||||
for (long ipN : gIpsSorted)
|
for (long ipN : gIpsSorted)
|
||||||
{
|
{
|
||||||
PutString(" Client_");
|
PutString(" Client_");
|
||||||
if (useThirdIpByteForNames)
|
switch (NodeNameStyle) // Add the IP bytes depending on the style. Don't break anywhere.
|
||||||
{
|
{
|
||||||
PutString(gIpsSorted[ipN].IpNet);
|
case WholeIp:
|
||||||
|
PutString(gIpsSorted[ipN].Ip1);
|
||||||
PutString("_");
|
PutString("_");
|
||||||
|
case ThreeLastBytes:
|
||||||
|
PutString(gIpsSorted[ipN].Ip2);
|
||||||
|
PutString("_");
|
||||||
|
case TwoLastBytes:
|
||||||
|
PutString(gIpsSorted[ipN].Ip3);
|
||||||
|
PutString("_");
|
||||||
|
case LastByte:
|
||||||
|
PutString(gIpsSorted[ipN].Ip4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writeDbg(MbError, "The NodeNameStyle %d is unknown, please use a value of the enum!", NodeNameStyle);
|
||||||
|
runError(1001, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
PutString(gIpsSorted[ipN].IpLsb);
|
|
||||||
}
|
}
|
||||||
PutString("\n\n\n\n");
|
PutString("\n\n\n\n");
|
||||||
PutString("BA_DEF_ BU_ \"NodeLayerModules\" STRING ;\n");
|
PutString("BA_DEF_ BU_ \"NodeLayerModules\" STRING ;\n");
|
||||||
|
@ -497,9 +512,7 @@ void GenDbc()
|
||||||
PutString("BA_DEF_DEF_ \"DBName\" \"\";\n");
|
PutString("BA_DEF_DEF_ \"DBName\" \"\";\n");
|
||||||
PutString("BA_DEF_DEF_ \"BusType\" \"Ethernet\";\n");
|
PutString("BA_DEF_DEF_ \"BusType\" \"Ethernet\";\n");
|
||||||
PutString("BA_ \"BusType\" \"Ethernet\";\n");
|
PutString("BA_ \"BusType\" \"Ethernet\";\n");
|
||||||
PutString("BA_ \"DBName\" \"");
|
PutString("BA_ \"DBName\" \"Modbus\";\n");
|
||||||
PutString(name);
|
|
||||||
PutString("\";\n");
|
|
||||||
|
|
||||||
f.Close();
|
f.Close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*@!Encoding:1252*/
|
/*@!Encoding:1252*/
|
||||||
|
|
||||||
// This file is the Modbus Client for Airbus CIDS
|
// This file is the Modbus Client for Airbus CIDS
|
||||||
// It automatically and periodically reads all input bits and registers and writes them to SysVars %BUSTYPE%%CHANNEL%::%NODE_NAME%::Data
|
// It automatically and periodically reads all input bits and registers and writes them to SysVars %BUSTYPE%::%NODE_NAME%::Data
|
||||||
// It also reacts on changes in the output SysVars and write those to the Modbus device.
|
// It also reacts on changes in the output SysVars and write those to the Modbus device.
|
||||||
|
|
||||||
includes
|
includes
|
||||||
|
@ -27,9 +27,9 @@ on preStart
|
||||||
on start
|
on start
|
||||||
{
|
{
|
||||||
char ip[16];
|
char ip[16];
|
||||||
sysGetVariableString("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config", "IP", ip, elCount(ip)); // Get IP address of device from sysvars config
|
sysGetVariableString("%BUS_TYPE%::%NODE_NAME%::Config", "IP", ip, elCount(ip)); // Get IP address of device from sysvars config
|
||||||
|
|
||||||
DeviceInit(@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::Vendor); // Set all device specific parameters (Wago / B&R)
|
DeviceInit(@sysvar::%BUS_TYPE%::%NODE_NAME%::Info::Vendor); // Set all device specific parameters (Wago / B&R)
|
||||||
|
|
||||||
writeDbg(MbInfo, "Connecting to %s:%d", ip, @sysvar::Config::Modbus::Port);
|
writeDbg(MbInfo, "Connecting to %s:%d", ip, @sysvar::Config::Modbus::Port);
|
||||||
ModbusInit(ip, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, @sysvar::Config::Modbus::MaxTransmissionCount); // 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
|
||||||
|
@ -37,11 +37,11 @@ on start
|
||||||
if (gSocketState < CONNECTING) // We are not connecting and not connected
|
if (gSocketState < CONNECTING) // We are not connecting and not connected
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ModbusReadOutBits(thisDev.Addr.Read.OutputBits, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits); // Read the start status of the output bits
|
ModbusReadOutBits(thisDev.Addr.Read.OutputBits, @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::OutputBits); // Read the start status of the output bits
|
||||||
ModbusReadOutRegisters(thisDev.Addr.Read.OutputRegisters, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters); // Read the start status of the output registers
|
ModbusReadOutRegisters(thisDev.Addr.Read.OutputRegisters, @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::OutputRegisters); // Read the start status of the output registers
|
||||||
|
|
||||||
if (@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config::Interval > 0) // Start the polling timer
|
if (@sysvar::%BUS_TYPE%::%NODE_NAME%::Config::Interval > 0) // Start the polling timer
|
||||||
setTimerCyclic(gtRead, 1, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config::Interval);
|
setTimerCyclic(gtRead, 1, @sysvar::%BUS_TYPE%::%NODE_NAME%::Config::Interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop all transactions and close connection
|
// Stop all transactions and close connection
|
||||||
|
@ -72,10 +72,10 @@ void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException
|
||||||
case NotSent:
|
case NotSent:
|
||||||
break;
|
break;
|
||||||
case FinalTimeout:
|
case FinalTimeout:
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
|
||||||
for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits; i++)
|
for (i = 0; i < @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputBits; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputBits[i] = -1;
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputBits[i] = -1;
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
writeDbg(MbError, "OnModbusReadBitsFailed: Unkown error: %d", error);
|
writeDbg(MbError, "OnModbusReadBitsFailed: Unkown error: %d", error);
|
||||||
|
@ -96,10 +96,10 @@ void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusExcep
|
||||||
case NotSent:
|
case NotSent:
|
||||||
break;
|
break;
|
||||||
case FinalTimeout:
|
case FinalTimeout:
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
|
||||||
for (i = 0; i < @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters; i++)
|
for (i = 0; i < @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputRegisters; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputRegisters[i] = -1;
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputRegisters[i] = -1;
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
writeDbg(MbError, "OnModbusReadBitsFailed: Unkown error: %d", error);
|
writeDbg(MbError, "OnModbusReadBitsFailed: Unkown error: %d", error);
|
||||||
|
@ -134,24 +134,24 @@ void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[]
|
||||||
switch (mbres.Header.FuncCode) // We assume that we separate between 0x01 and 0x02 even though the address space may be the same
|
switch (mbres.Header.FuncCode) // We assume that we separate between 0x01 and 0x02 even though the address space may be the same
|
||||||
{
|
{
|
||||||
case ReadBitsOut: // Read output bits
|
case ReadBitsOut: // Read output bits
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputBits");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "OutputBits");
|
||||||
|
|
||||||
offset = mbreq.Address - thisDev.Addr.Read.OutputBits; // Get the offset to the base output bit address
|
offset = mbreq.Address - thisDev.Addr.Read.OutputBits; // Get the offset to the base output bit address
|
||||||
for (i = 0; i < mbreq.Count; i++)
|
for (i = 0; i < mbreq.Count; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits[i + offset] = bitStatus[i];
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::OutputBits[i + offset] = bitStatus[i];
|
||||||
|
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputBits");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "OutputBits");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case ReadBitsIn: // Read input bits
|
case ReadBitsIn: // Read input bits
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
|
||||||
|
|
||||||
offset = mbreq.Address - thisDev.Addr.Read.InputBits; // Get the offset to the base input bit address
|
offset = mbreq.Address - thisDev.Addr.Read.InputBits; // Get the offset to the base input bit address
|
||||||
for (i = 0; i < mbreq.Count; i++)
|
for (i = 0; i < mbreq.Count; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputBits[i + offset] = bitStatus[i];
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputBits[i + offset] = bitStatus[i];
|
||||||
|
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputBits");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputBits");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -169,24 +169,24 @@ void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct
|
||||||
switch (mbres.Header.FuncCode) // We assume that we separate between 0x03 and 0x04 even though the address space may be the same
|
switch (mbres.Header.FuncCode) // We assume that we separate between 0x03 and 0x04 even though the address space may be the same
|
||||||
{
|
{
|
||||||
case ReadRegistersOut: // Read output registers
|
case ReadRegistersOut: // Read output registers
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputRegisters");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "OutputRegisters");
|
||||||
|
|
||||||
offset = mbreq.Address - thisDev.Addr.Read.OutputRegisters; // Get the offset to the base output register address
|
offset = mbreq.Address - thisDev.Addr.Read.OutputRegisters; // Get the offset to the base output register address
|
||||||
for (i = 0; i < mbreq.Count; i++)
|
for (i = 0; i < mbreq.Count; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputRegisters[i + offset] = mbres.Data[i];
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::OutputRegisters[i + offset] = mbres.Data[i];
|
||||||
|
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "OutputRegisters");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "OutputRegisters");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case ReadRegistersIn: // Read input registers
|
case ReadRegistersIn: // Read input registers
|
||||||
sysBeginVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
|
sysBeginVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
|
||||||
|
|
||||||
offset = mbreq.Address - thisDev.Addr.Read.InputRegisters; // Get the offset to the base input bit address
|
offset = mbreq.Address - thisDev.Addr.Read.InputRegisters; // Get the offset to the base input bit address
|
||||||
for (i = 0; i < mbreq.Count; i++)
|
for (i = 0; i < mbreq.Count; i++)
|
||||||
@sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::InputRegisters[i + offset] = mbres.Data[i];
|
@sysvar::%BUS_TYPE%::%NODE_NAME%::Data::InputRegisters[i + offset] = mbres.Data[i];
|
||||||
|
|
||||||
sysEndVariableStructUpdate("%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data", "InputRegisters");
|
sysEndVariableStructUpdate("%BUS_TYPE%::%NODE_NAME%::Data", "InputRegisters");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -250,38 +250,38 @@ void OnModbusClientPanics(enum FatalErrors reason)
|
||||||
// The timer will continuously poll the input registers and intput bits
|
// The timer will continuously poll the input registers and intput bits
|
||||||
on timer gtRead
|
on timer gtRead
|
||||||
{
|
{
|
||||||
ModbusReadRegisters(thisDev.Addr.Read.InputRegisters, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputRegisters);
|
ModbusReadRegisters(thisDev.Addr.Read.InputRegisters, @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputRegisters);
|
||||||
ModbusReadBits(thisDev.Addr.Read.InputBits, @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::InputBits);
|
ModbusReadBits(thisDev.Addr.Read.InputBits, @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::InputBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Data::OutputBits is changed we will send this update to the device
|
// If Data::OutputBits is changed we will send this update to the device
|
||||||
on sysvar %BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits
|
on sysvar %BUS_TYPE%::%NODE_NAME%::Data::OutputBits
|
||||||
{
|
{
|
||||||
word count, i;
|
word count, i;
|
||||||
byte bitStatus[1968];
|
byte bitStatus[1968];
|
||||||
|
|
||||||
count = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputBits;
|
count = @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::OutputBits;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) // Copy the data from SysVars to byte[]
|
for (i = 0; i < count; i++) // Copy the data from SysVars to byte[]
|
||||||
bitStatus[i] = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputBits[i];
|
bitStatus[i] = @sysvar::%BUS_TYPE%::%NODE_NAME%::Data::OutputBits[i];
|
||||||
|
|
||||||
ModbusWriteBitsB(0, count, bitStatus); // Send update command
|
ModbusWriteBitsB(0, count, bitStatus); // Send update command
|
||||||
}
|
}
|
||||||
// If Data::OutputRergisters is changed we will send this update to the device
|
// If Data::OutputRergisters is changed we will send this update to the device
|
||||||
on sysvar %BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputRegisters
|
on sysvar %BUS_TYPE%::%NODE_NAME%::Data::OutputRegisters
|
||||||
{
|
{
|
||||||
word count, i;
|
word count, i;
|
||||||
word regValues[123];
|
word regValues[123];
|
||||||
|
|
||||||
count = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Info::OutputRegisters;
|
count = @sysvar::%BUS_TYPE%::%NODE_NAME%::Info::OutputRegisters;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) // Copy the data from SysVars to word[]
|
for (i = 0; i < count; i++) // Copy the data from SysVars to word[]
|
||||||
regValues[i] = @sysvar::%BUS_TYPE%%CHANNEL%::%NODE_NAME%::Data::OutputRegisters[i];
|
regValues[i] = @sysvar::%BUS_TYPE%::%NODE_NAME%::Data::OutputRegisters[i];
|
||||||
|
|
||||||
ModbusWriteRegisters(0, count, regValues); // Send update command
|
ModbusWriteRegisters(0, count, regValues); // Send update command
|
||||||
}
|
}
|
||||||
// Config::Interval is changed we will update the timer gtRead accordingly
|
// Config::Interval is changed we will update the timer gtRead accordingly
|
||||||
on sysvar %BUS_TYPE%%CHANNEL%::%NODE_NAME%::Config::Interval
|
on sysvar %BUS_TYPE%::%NODE_NAME%::Config::Interval
|
||||||
{
|
{
|
||||||
if (@this <= 0)
|
if (@this <= 0)
|
||||||
gtRead.Cancel();
|
gtRead.Cancel();
|
||||||
|
|
|
@ -53,8 +53,10 @@ variables
|
||||||
struct device // A structure that contains information about an Modbus device. Used in MakeConfig.
|
struct device // A structure that contains information about an Modbus device. Used in MakeConfig.
|
||||||
{
|
{
|
||||||
char Ip[16]; // String: The IP address
|
char Ip[16]; // String: The IP address
|
||||||
char IpLsb[4]; // String: The last byte of the IP address. Used as index of node name
|
char Ip4[4]; // String: The last byte of the IP address.
|
||||||
char IpNet[4]; // String: The second last byte of the IP. Used as index of net
|
char Ip3[4]; // String: The third byte of the IP.
|
||||||
|
char Ip2[4]; // String: The second byte of the IP.
|
||||||
|
char Ip1[4]; // String: Thefirst byte of the IP.
|
||||||
enum Vendor Vendor; // The Vendor (Wago / B&R)
|
enum Vendor Vendor; // The Vendor (Wago / B&R)
|
||||||
word SerialCode; // Serial Code
|
word SerialCode; // Serial Code
|
||||||
word DeviceCode; // Device Code
|
word DeviceCode; // Device Code
|
||||||
|
|
Loading…
Reference in a new issue