Jonny007-MKD
84ab39d5b3
Counting the send attempts to reject packets that cannot be send (e.g. wrong network) MakeConfig.can Introduced options (skip255 and useThirdIpNameForNodeName)
547 lines
No EOL
23 KiB
Text
547 lines
No EOL
23 KiB
Text
/*@!Encoding:1252*/
|
|
includes
|
|
{
|
|
#include "include/DeviceInformation.cin"
|
|
#include "include/ModbusUdp.cin"
|
|
#include "include/ModbusClient.cin"
|
|
}
|
|
|
|
variables
|
|
{
|
|
char[16] gIps[long]; // List IP addresses. These will be analysed
|
|
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 fnSysvar[40]; // Filename of Sysvars
|
|
char fnDbc[40]; // Filename of DBC
|
|
char name[20]; // Name of project (not important)
|
|
dword ips[50]; // detected IPs. We need this array for enumeration with integers
|
|
|
|
|
|
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
|
|
dword gScanFirst, gScanLast; // The first and last IP address as dword
|
|
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
|
|
{
|
|
byte i = 0;
|
|
// List of IPs of devices goes here
|
|
///strncpy(gIps[i++], "192.168.1.100", 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
|
|
// 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.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));
|
|
|
|
// Paths to the generated files relative to MakeConfig.cfg
|
|
strncpy(fnSysvar, "include/SysVars/generated.vsysvar", elCount(fnSysvar));
|
|
strncpy(fnDbc, "include/DBC/generated.dbc", elCount(fnDbc));
|
|
|
|
OutputDebugLevel = Error;
|
|
}
|
|
|
|
on start
|
|
{
|
|
ggMaxTransmissionCount = @sysvar::Config::Modbus::MaxTransmissionCount; // save the value
|
|
|
|
DeviceInit(All);
|
|
if (gIps.Size() == 0) // if no IP address were specified
|
|
DetectDevices(); // scan network for devices (Step1)
|
|
else
|
|
MakeIpNets(); // else continue with Step2
|
|
}
|
|
|
|
/// <PutString>
|
|
void PutString(char str[])
|
|
{
|
|
f.PutString(str, strlen(str));
|
|
}
|
|
/// <PutString>
|
|
void PutString(word d)
|
|
{
|
|
char str[6];
|
|
ltoa(d, str, 10);
|
|
f.PutString(str, strlen(str));
|
|
}
|
|
/// <PutString>
|
|
void PutString(byte d)
|
|
{
|
|
char str[4];
|
|
ltoa(d, str, 10);
|
|
f.PutString(str, strlen(str));
|
|
}
|
|
|
|
// Step 1: Detect active devices and collect IP addresses
|
|
// This function will convert the IP address, open the socket and start the detection. The rest will be done by events
|
|
/// <Step1>
|
|
void DetectDevices()
|
|
{
|
|
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 :)
|
|
|
|
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24);
|
|
ModbusInit(gScanFirstIp, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, 1); // Open socket and set variables
|
|
ModbusReadBits(0, 1); // Start device detection
|
|
}
|
|
// This function will increment the IP address and continue the detection
|
|
/// <Step1>
|
|
void DetectDevicesNext()
|
|
{
|
|
gScanFirst = swapDWord(gScanFirst);
|
|
gScanFirst++;
|
|
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)
|
|
{
|
|
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount;
|
|
MakeIpNets();
|
|
return;
|
|
}
|
|
|
|
gScanFirst = swapDWord(gScanFirst);
|
|
|
|
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!
|
|
ModbusReadBits(0, 1); // Scan the next device
|
|
}
|
|
/// <Step1>
|
|
void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
|
|
{
|
|
DetectDevicesNext(); // Timeout, NotSent, Exception! We will go to the next device
|
|
}
|
|
/// <Step1>
|
|
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq)
|
|
{
|
|
ipGetAddressAsString(gScanFirst, gIps[gScanFirst], 16); // store the detected device's IP address
|
|
DetectDevicesNext(); // and continue
|
|
}
|
|
|
|
|
|
// Step 2: Sort into subnets and create structure
|
|
// Sort the IPs from gIps to gIpsSorted and add their subnet to gIpNets
|
|
/// <Step2>
|
|
void MakeIpNets()
|
|
{
|
|
long ipNum;
|
|
|
|
if (gIps.Size() == 0) // If no devices were specified and detected
|
|
{
|
|
writeDbg(MbError, "No devices found!");
|
|
stop(); // Don't do anything
|
|
return;
|
|
}
|
|
|
|
for (long i : gIps) // Go through all devices
|
|
{
|
|
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
|
|
// fill the device structure array:
|
|
strncpy(gIpsSorted[ipNum].IP, gIps[i], 16); // set .IP
|
|
ltoa((ipNum >> 16) & 0xFF, gIpsSorted[ipNum].IpNet, 10); // set .IpNet
|
|
ltoa((ipNum >> 24) & 0xFF, gIpsSorted[ipNum].IpLsb, 10); // set .IpLsb
|
|
|
|
gIps.Remove(i);
|
|
}
|
|
|
|
AnalyzeDevices(); // Continue with step 3
|
|
}
|
|
|
|
|
|
// Step 3: Retreive configuration of devices
|
|
/// <Step3>
|
|
void AnalyzeDevices()
|
|
{
|
|
// Init counters
|
|
ADn = 1; // expect 10 responses
|
|
ADi = 0; // First IP address
|
|
ADl = gIpsSorted.Size();
|
|
|
|
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
|
|
|
|
if (gRemoteIP != INVALID_IP) // If we already do have a socket
|
|
gRemoteIP = ips[ADi]; // use it
|
|
else // else create a new one
|
|
_ModbusConnectTo(ips[ADi], @sysvar::Config::Modbus::Port);
|
|
|
|
// request something special to get the vendor
|
|
// since there is no common register that holds the vendor
|
|
// we have to send a request that only one device responds correctly.
|
|
// At 0x1000-0x1002 B&R devices return the MAC address, whereas Wago holds the WatchdogTime.
|
|
// As the watchdog time only consists of 1 word Wago will return a IllegalDataAddress exception (0x02)
|
|
ModbusReadRegisters(0x1000, 3); // Request B&R MAC address
|
|
}
|
|
/// <Step3>
|
|
void AnalyzeDevicesNext()
|
|
{
|
|
if (strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules) > 0)
|
|
gIpsSorted[ips[ADi]].DeviceIOs.Modules[strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules)-1] = 0;
|
|
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
|
|
{
|
|
MakeFiles(); // go to Step4
|
|
return;
|
|
}
|
|
|
|
ADn = 1; // expect 10 responses
|
|
gRemoteIP = ips[ADi]; // Next IP address
|
|
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
|
|
// request something special to get the vendor
|
|
ModbusReadRegisters(0x1000, 3); // Request B&R MAC address
|
|
}
|
|
/// <Step3>
|
|
void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
|
|
{
|
|
struct ModbusReqRead mbreq;
|
|
|
|
switch (error)
|
|
{
|
|
case Timeout:
|
|
return;
|
|
case Exception:
|
|
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
|
|
{
|
|
gIpsSorted[ips[ADi]].Vendor = Wago;
|
|
// request information
|
|
ADn = _DeviceGetInformation(Wago);
|
|
return;
|
|
}
|
|
|
|
writeLineEx(0, 3, "Error while analyzing %s! The device respond with exception code %d! Ignoring...", gIpsSorted[ips[ADi]].IP, ex);
|
|
break;
|
|
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();
|
|
gQueueSent.Clear();
|
|
gIpsSorted.Remove(ips[ADi]); // Remove the IP
|
|
AnalyzeDevicesNext(); // And go to the next device
|
|
}
|
|
/// <Step3>
|
|
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq)
|
|
{
|
|
if (mbreq.Address == 0x1000) // We detected a B&R device
|
|
{
|
|
gIpsSorted[ips[ADi]].Vendor = BuR;
|
|
|
|
// request further information
|
|
ADn = _DeviceGetInformation(BuR);
|
|
return;
|
|
}
|
|
|
|
_DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count);
|
|
|
|
if (--ADn == 0) // If we received all registers
|
|
AnalyzeDevicesNext();
|
|
}
|
|
|
|
// Step 4: Create the files with the queried data
|
|
/// <Step4>
|
|
void MakeFiles()
|
|
{
|
|
GenSysvars();
|
|
GenDbc();
|
|
stop();
|
|
}
|
|
|
|
// Generate the SysVars XML
|
|
/// <Step4>
|
|
void GenSysvars()
|
|
{
|
|
write("GenSysvars() -> %s", fnSysvar);
|
|
f.Open(fnSysvar, 0, 0); // rewrite file in ASCII
|
|
|
|
PutString("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
|
PutString("<systemvariables version=\"4\">\n");
|
|
PutString(" <namespace name=\"\" comment=\"\">\n");
|
|
|
|
PutString(" <namespace name=\"Config\" comment=\"\">\n");
|
|
PutString(" <namespace name=\"Modbus\" comment=\"\">\n");
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"ms\" name=\"RequestTimeout\" comment=\"The maximum duration for a Modbus-UDP/-TCP request in milliseconds. After timeout a retransmission may be started (see MaxRetransmissionCount). Use `ping` to get the maximum latency to a device, double it and add 2-3 ms for processing.\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString((word)@sysvar::Config::Modbus::RequestTimeout);
|
|
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"1000\" maxValuePhys=\"1000\" />\n");
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"Port\" comment=\"\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString((word)@sysvar::Config::Modbus::Port);
|
|
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"65535\" maxValuePhys=\"65535\" />\n");
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"times\" name=\"MaxTransmissionCount\" comment=\"How often a retransmission of a request will be sent until it gets discarded and an error is thrown.\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString((byte)@sysvar::Config::Modbus::MaxTransmissionCount);
|
|
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10\" maxValuePhys=\"10\" />\n");
|
|
PutString(" </namespace>\n");
|
|
PutString(" <namespace name=\"TcpIp\" comment=\"\">\n");
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"AdapterIndex\" comment=\"Index of network interface to use\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"2\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"20\" maxValuePhys=\"20\" />\n");
|
|
PutString(" </namespace>\n");
|
|
PutString(" </namespace>\n");
|
|
|
|
for (long net : gIpNets)
|
|
{
|
|
byte nett;
|
|
nett = net;
|
|
PutString(" <namespace name=\"Ethernet");
|
|
PutString(nett);
|
|
PutString("\" comment=\"Subnet: 192.168.");
|
|
PutString(nett);
|
|
PutString(".\">\n");
|
|
|
|
for (long ipN : gIpsSorted)
|
|
{
|
|
if (((ipN >> 16) & 0xFF) != net)
|
|
continue;
|
|
DeviceInit(gIpsSorted[ipN].Vendor);
|
|
|
|
PutString(" <namespace name=\"Client_");
|
|
if (useThirdIpByteForNames)
|
|
{
|
|
PutString(gIpsSorted[ipN].IpNet);
|
|
PutString("_");
|
|
}
|
|
PutString(gIpsSorted[ipN].IpLsb);
|
|
PutString("\" comment=\"Server with ip address '");
|
|
PutString(gIpsSorted[ipN].Ip);
|
|
PutString("'\">\n");
|
|
|
|
// Namespace Config
|
|
PutString(" <namespace name=\"Config\" comment=\"Configuration section for this server\">\n");
|
|
// IP
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"IP\" comment=\"The IP address of this server\" bitcount=\"8\" isSigned=\"true\" encoding=\"65001\" type=\"string\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].Ip);
|
|
PutString("\" />\n");
|
|
// Intveral
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"ms\" name=\"Interval\" comment=\"The interval with which the device will be queried\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"100\" minValue=\"10\" minValuePhys=\"10\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n");
|
|
PutString(" </namespace>\n");
|
|
|
|
//Namespace Info
|
|
PutString(" <namespace name=\"Info\" comment=\"Some information about the device\">\n");
|
|
// Vendor
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"Vendor\" comment=\"The vendor of the device\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString((byte)gIpsSorted[ipN].Vendor);
|
|
PutString("\">\n");
|
|
PutString(" <valuetable definesMinMax=\"true\">\n");
|
|
PutString(" <valuetableentry value=\"2\" description=\"BuR\" />\n");
|
|
PutString(" <valuetableentry value=\"23\" description=\"Wago\" />\n");
|
|
PutString(" </valuetable>\n");
|
|
PutString(" </variable>\n");
|
|
// SerialCode
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"SerialCode\" comment=\"The serial code of the server\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].SerialCode);
|
|
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n");
|
|
// DeviceCode
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"DeviceCode\" comment=\"The device code of the server\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceCode);
|
|
PutString("\" minValue=\"1\" minValuePhys=\"1\" maxValue=\"10000\" maxValuePhys=\"10000\" />\n");
|
|
// Modules
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"Modules\" comment=\"The type and number of inputs of modules that are connected to the server\" bitcount=\"8\" isSigned=\"true\" encoding=\"65001\" type=\"string\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.Modules);
|
|
PutString("\" />\n");
|
|
// InputRegisters
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"InputRegisters\" comment=\"Number of input registers\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.InputRegisters);
|
|
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
|
|
PutString((word)thisDev.MaxRegisterCount);
|
|
PutString("\" maxValuePhys=\"");
|
|
PutString((word)thisDev.MaxRegisterCount);
|
|
PutString("\" />\n");
|
|
// InputBits
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"InputBits\" comment=\"Number of input bits\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.InputBits);
|
|
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
|
|
PutString((word)thisDev.MaxBitCount);
|
|
PutString("\" maxValuePhys=\"");
|
|
PutString((word)thisDev.MaxBitCount);
|
|
PutString("\" />\n");
|
|
// OutputRegisters
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"OutputRegisters\" comment=\"Number of output registers\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.OutputRegisters);
|
|
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
|
|
PutString((word)thisDev.MaxRegisterCount);
|
|
PutString("\" maxValuePhys=\"");
|
|
PutString((word)thisDev.MaxRegisterCount);
|
|
PutString("\" />\n");
|
|
// OutputBits
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"true\" valueSequence=\"false\" unit=\"\" name=\"OutputBits\" comment=\"Number of output bits\" bitcount=\"32\" isSigned=\"true\" encoding=\"65001\" type=\"int\" startValue=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.OutputBits);
|
|
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
|
|
PutString((word)thisDev.MaxBitCount);
|
|
PutString("\" maxValuePhys=\"");
|
|
PutString((word)thisDev.MaxBitCount);
|
|
PutString("\" />\n");
|
|
PutString(" </namespace>\n");
|
|
|
|
// Namespace Data
|
|
PutString(" <namespace name=\"Data\" comment=\"The actual process image\">\n");
|
|
// InputRegisters
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"InputRegisters\" comment=\"The values of the input registers\" bitcount=\"9\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.InputRegisters);
|
|
PutString("\" />\n");
|
|
// InputBits
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"InputBits\" comment=\"The state of the input bits\" bitcount=\"2\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.InputBits);
|
|
PutString("\" />\n");
|
|
// OutputRegisters
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"OutputRegisters\" comment=\"The values of the output registers. Write here and the values will be sent to the device\" bitcount=\"9\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.OutputRegisters);
|
|
PutString("\" />\n");
|
|
// OutputBits
|
|
PutString(" <variable anlyzLocal=\"2\" readOnly=\"false\" valueSequence=\"false\" unit=\"\" name=\"OutputBits\" comment=\"The state of the output bits. Write here and the values will be sent to the device\" bitcount=\"2\" isSigned=\"true\" encoding=\"65001\" type=\"intarray\" arrayLength=\"");
|
|
PutString(gIpsSorted[ipN].DeviceIOs.OutputBits);
|
|
PutString("\" />\n");
|
|
|
|
PutString(" </namespace>\n");
|
|
PutString(" </namespace>\n");
|
|
}
|
|
PutString(" </namespace>\n");
|
|
}
|
|
|
|
PutString(" </namespace>\n");
|
|
PutString("</systemvariables>\n");
|
|
|
|
f.Close();
|
|
}
|
|
|
|
// Generate the Database
|
|
/// <Step4>
|
|
void GenDbc()
|
|
{
|
|
write("GenDbc() -> %s", fnDbc);
|
|
f.Open(fnDbc, 0, 0); // rewrite file in ASCII
|
|
|
|
PutString("VERSION \"\"\n\n\n");
|
|
PutString("NS_ :\n");
|
|
PutString(" NS_DESC_\n");
|
|
PutString(" CM_\n");
|
|
PutString(" BA_DEF_\n");
|
|
PutString(" BA_\n");
|
|
PutString(" VAL_\n");
|
|
PutString(" CAT_DEF_\n");
|
|
PutString(" CAT_\n");
|
|
PutString(" FILTER\n");
|
|
PutString(" BA_DEF_DEF_\n");
|
|
PutString(" EV_DATA_\n");
|
|
PutString(" ENVVAR_DATA_\n");
|
|
PutString(" SGTYPE_\n");
|
|
PutString(" SGTYPE_VAL_\n");
|
|
PutString(" BA_DEF_SGTYPE_\n");
|
|
PutString(" BA_SGTYPE_\n");
|
|
PutString(" SIG_TYPE_REF_\n");
|
|
PutString(" VAL_TABLE_\n");
|
|
PutString(" SIG_GROUP_\n");
|
|
PutString(" SIG_VALTYPE_\n");
|
|
PutString(" SIGTYPE_VALTYPE_\n");
|
|
PutString(" BO_TX_BU_\n");
|
|
PutString(" BA_DEF_REL_\n");
|
|
PutString(" BA_REL_\n");
|
|
PutString(" BA_DEF_DEF_REL_\n");
|
|
PutString(" BU_SG_REL_\n");
|
|
PutString(" BU_EV_REL_\n");
|
|
PutString(" BU_BO_REL_\n");
|
|
PutString(" SG_MUL_VAL_\n");
|
|
PutString("\n");
|
|
PutString("BS_:\n");
|
|
PutString("\nBU_:");
|
|
|
|
for (long ipN : gIpsSorted)
|
|
{
|
|
PutString(" Client_");
|
|
if (useThirdIpByteForNames)
|
|
{
|
|
PutString(gIpsSorted[ipN].IpNet);
|
|
PutString("_");
|
|
}
|
|
PutString(gIpsSorted[ipN].IpLsb);
|
|
}
|
|
PutString("\n\n\n\n");
|
|
PutString("BA_DEF_ BU_ \"NodeLayerModules\" STRING ;\n");
|
|
PutString("BA_DEF_ \"DBName\" STRING ;\n");
|
|
PutString("BA_DEF_ \"BusType\" STRING ;\n");
|
|
PutString("BA_DEF_DEF_ \"NodeLayerModules\" \"Ethernet_IL.DLL\";\n");
|
|
PutString("BA_DEF_DEF_ \"DBName\" \"\";\n");
|
|
PutString("BA_DEF_DEF_ \"BusType\" \"Ethernet\";\n");
|
|
PutString("BA_ \"BusType\" \"Ethernet\";\n");
|
|
PutString("BA_ \"DBName\" \"");
|
|
PutString(name);
|
|
PutString("\";\n");
|
|
|
|
f.Close();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The stuff below is not needed
|
|
/// <zzzModbus>
|
|
void OnModbusClientPanics(enum FatalErrors reason)
|
|
{
|
|
writeLineEx(0, 4, "<%NODE_NAME%> FATAL! %d", reason);
|
|
/* switch(reason)
|
|
{
|
|
case ParsingBuffer:
|
|
case ModbusPackageWasSplit:
|
|
case DeviceCodeUnknown:
|
|
case VendorIdUnknown:
|
|
case ConnectionError:
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteBitFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteRegisterFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteMasksFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusReadWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbc){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbc){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbc){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbc){}
|
|
/// <zzzModbus>
|
|
void OnModbusWriteMasksSuccess(struct ModbusResConfirmMasks mbc){} |