2014-05-21 13:37:57 +02:00
/*@!Encoding:1252*/
includes
{
2014-06-17 16:21:45 +02:00
#include "include/DeviceInformation.cin"
2014-07-10 09:56:55 +02:00
#include "include/ModbusUdp.cin"
#include "include/ModbusClient.cin"
2014-05-21 13:37:57 +02:00
}
variables
{
2014-06-12 17:28:05 +02:00
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.
2014-05-21 13:37:57 +02:00
2014-06-12 17:28:05 +02:00
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
2014-05-26 12:07:04 +02:00
2014-05-21 13:37:57 +02:00
2014-06-12 17:28:05 +02:00
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"
2014-05-26 13:58:28 +02:00
2014-07-10 09:56:55 +02:00
byte ggMaxTransmissionCount;
2014-07-11 13:32:02 +02:00
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
2014-05-21 13:37:57 +02:00
}
on preStart
2014-05-26 13:58:28 +02:00
{
2014-07-10 09:56:55 +02:00
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));
2014-05-21 13:37:57 +02:00
2014-06-17 16:21:45 +02:00
// Scan a range of IPs for devices (if nothing was set above). Start and Stop go here
2014-07-10 09:56:55 +02:00
// Please note: Currently .255 will be skipped! Don't use this address for devices
strncpy(gScanFirstIp, "192.168.1.2", elCount(gScanFirstIp));
2014-07-11 13:32:02 +02:00
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;
2014-05-21 13:37:57 +02:00
2014-05-26 13:58:28 +02:00
// Name of the project
2014-05-21 13:37:57 +02:00
strncpy(name, "Modbus", elCount(name));
2014-06-12 17:28:05 +02:00
// Paths to the generated files relative to MakeConfig.cfg
2014-05-26 12:22:46 +02:00
strncpy(fnSysvar, "include/SysVars/generated.vsysvar", elCount(fnSysvar));
strncpy(fnDbc, "include/DBC/generated.dbc", elCount(fnDbc));
2014-06-12 17:28:05 +02:00
2014-07-11 13:32:02 +02:00
OutputDebugLevel = Error;
2014-05-21 13:37:57 +02:00
}
on start
{
2014-07-10 09:56:55 +02:00
ggMaxTransmissionCount = @sysvar::Config::Modbus::MaxTransmissionCount; // save the value
2014-05-26 13:58:28 +02:00
2014-07-10 09:56:55 +02:00
DeviceInit(All);
2014-06-12 17:28:05 +02:00
if (gIps.Size() == 0) // if no IP address were specified
DetectDevices(); // scan network for devices (Step1)
2014-05-21 13:37:57 +02:00
else
2014-06-12 17:28:05 +02:00
MakeIpNets(); // else continue with Step2
2014-05-21 13:37:57 +02:00
}
2014-05-26 13:58:28 +02:00
/// <PutString>
2014-06-12 17:28:05 +02:00
void PutString(char str[])
2014-05-21 13:37:57 +02:00
{
f.PutString(str, strlen(str));
}
2014-05-26 13:58:28 +02:00
/// <PutString>
2014-06-12 17:28:05 +02:00
void PutString(word d)
2014-05-26 12:07:04 +02:00
{
char str[6];
ltoa(d, str, 10);
f.PutString(str, strlen(str));
}
2014-05-26 13:58:28 +02:00
/// <PutString>
2014-06-12 17:28:05 +02:00
void PutString(byte d)
2014-05-26 12:07:04 +02:00
{
char str[4];
ltoa(d, str, 10);
f.PutString(str, strlen(str));
}
2014-05-21 13:37:57 +02:00
2014-05-26 12:07:04 +02:00
// Step 1: Detect active devices and collect IP addresses
2014-06-12 17:28:05 +02:00
// This function will convert the IP address, open the socket and start the detection. The rest will be done by events
2014-05-26 12:07:04 +02:00
/// <Step1>
void DetectDevices()
2014-05-21 13:37:57 +02:00
{
2014-07-11 13:32:02 +02:00
writeLineEx(0, 1, "Scanning from %s to %s with timeout of %d ms", gScanFirstIp, gScanLastIp, @sysvar::Config::Modbus::RequestTimeout);
2014-06-12 17:28:05 +02:00
2014-07-10 09:56:55 +02:00
gScanFirst = ipGetAddressAsNumber(gScanFirstIp); // We have to use big endian here
gScanLast = swapDWord(ipGetAddressAsNumber(gScanLastIp)); // But not here :)
2014-06-12 17:28:05 +02:00
2014-06-17 16:21:45 +02:00
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst & 0xFF, (gScanFirst >> 8) & 0xFF, (gScanFirst >> 16) & 0xFF, gScanFirst >> 24);
2014-07-10 09:56:55 +02:00
ModbusInit(gScanFirstIp, @sysvar::Config::Modbus::Port, @sysvar::Config::Modbus::RequestTimeout, 1); // Open socket and set variables
2014-06-12 17:28:05 +02:00
ModbusReadBits(0, 1); // Start device detection
2014-05-26 12:07:04 +02:00
}
2014-06-12 17:28:05 +02:00
// This function will increment the IP address and continue the detection
2014-05-26 12:07:04 +02:00
/// <Step1>
void DetectDevicesNext()
{
2014-06-17 16:21:45 +02:00
gScanFirst = swapDWord(gScanFirst);
gScanFirst++;
2014-07-11 13:32:02 +02:00
if (skip255 && (gScanFirst & 0xFF) == 0xFF) // skip .255
2014-05-26 12:07:04 +02:00
{
2014-06-17 16:21:45 +02:00
gScanFirst++;
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF);
2014-05-26 12:07:04 +02:00
}
2014-07-11 13:32:02 +02:00
else if (!skip255 && (gScanFirst & 0xFF) == 0x00)
{
writeLineEx(0, 0, "%d.%d.%d.%d ", gScanFirst >> 24, (gScanFirst >> 16) & 0xFF, (gScanFirst >> 8) & 0xFF, gScanFirst & 0xFF);
}
2014-06-12 17:28:05 +02:00
2014-06-17 16:21:45 +02:00
if (gScanFirst > gScanLast)
2014-05-26 12:07:04 +02:00
{
2014-07-10 09:56:55 +02:00
@sysvar::Config::Modbus::MaxTransmissionCount = ggMaxTransmissionCount;
2014-05-26 12:07:04 +02:00
MakeIpNets();
return;
}
2014-06-12 17:28:05 +02:00
2014-06-17 16:21:45 +02:00
gScanFirst = swapDWord(gScanFirst);
writeEx(0, 0, "."); // Write something so the user knows something is happening
2014-06-12 17:28:05 +02:00
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
2014-05-26 12:07:04 +02:00
}
/// <Step1>
void OnModbusReadBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
{
2014-07-11 13:32:02 +02:00
DetectDevicesNext(); // Timeout, NotSent, Exception! We will go to the next device
2014-05-26 12:07:04 +02:00
}
/// <Step1>
2014-05-27 13:29:24 +02:00
void OnModbusReadBitsSuccess(struct ModbusResReceiveBits mbres, byte bitStatus[], struct ModbusReqRead mbreq)
2014-05-26 12:07:04 +02:00
{
2014-06-12 17:28:05 +02:00
ipGetAddressAsString(gScanFirst, gIps[gScanFirst], 16); // store the detected device's IP address
DetectDevicesNext(); // and continue
2014-05-21 13:37:57 +02:00
}
2014-06-12 17:28:05 +02:00
// Step 2: Sort into subnets and create structure
2014-05-21 13:37:57 +02:00
// Sort the IPs from gIps to gIpsSorted and add their subnet to gIpNets
2014-05-26 12:07:04 +02:00
/// <Step2>
2014-05-21 13:37:57 +02:00
void MakeIpNets()
{
2014-05-26 12:07:04 +02:00
long ipNum;
2014-06-12 17:28:05 +02:00
if (gIps.Size() == 0) // If no devices were specified and detected
2014-05-26 12:07:04 +02:00
{
2014-07-10 09:56:55 +02:00
writeDbg(MbError, "No devices found!");
2014-06-12 17:28:05 +02:00
stop(); // Don't do anything
2014-05-26 12:07:04 +02:00
return;
}
2014-06-12 17:28:05 +02:00
for (long i : gIps) // Go through all devices
2014-05-21 13:37:57 +02:00
{
2014-05-26 12:07:04 +02:00
ipNum = ipGetAddressAsNumber(gIps[i]); // convert IP to dword
2014-06-12 17:28:05 +02:00
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
2014-05-26 12:07:04 +02:00
2014-05-21 13:37:57 +02:00
gIps.Remove(i);
2014-05-26 12:07:04 +02:00
}
2014-06-12 17:28:05 +02:00
AnalyzeDevices(); // Continue with step 3
2014-05-26 12:07:04 +02:00
}
// Step 3: Retreive configuration of devices
/// <Step3>
void AnalyzeDevices()
{
2014-06-12 17:28:05 +02:00
// Init counters
2014-06-16 14:50:35 +02:00
ADn = 1; // expect 10 responses
2014-06-12 17:28:05 +02:00
ADi = 0; // First IP address
2014-05-26 12:07:04 +02:00
ADl = gIpsSorted.Size();
2014-06-12 17:28:05 +02:00
2014-06-12 19:01:37 +02:00
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
2014-06-12 17:28:05 +02:00
if (gRemoteIP != INVALID_IP) // If we already do have a socket
gRemoteIP = ips[ADi]; // use it
else // else create a new one
2014-07-10 09:56:55 +02:00
_ModbusConnectTo(ips[ADi], @sysvar::Config::Modbus::Port);
2014-06-12 17:28:05 +02:00
2014-06-16 14:50:35 +02:00
// 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
2014-05-26 12:07:04 +02:00
}
/// <Step3>
void AnalyzeDevicesNext()
{
2014-06-16 14:50:35 +02:00
if (strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules) > 0)
gIpsSorted[ips[ADi]].DeviceIOs.Modules[strlen(gIpsSorted[ips[ADi]].DeviceIOs.Modules)-1] = 0;
2014-06-12 19:01:37 +02:00
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);
2014-05-26 12:07:04 +02:00
if (++ADi >= ADl) // we have analyzed all devices
{
2014-06-12 17:28:05 +02:00
MakeFiles(); // go to Step4
2014-05-26 12:07:04 +02:00
return;
}
2014-06-16 14:50:35 +02:00
ADn = 1; // expect 10 responses
2014-06-12 17:28:05 +02:00
gRemoteIP = ips[ADi]; // Next IP address
2014-06-12 19:01:37 +02:00
writeLineEx(0, 1, "Analyzing %s", gIpsSorted[ips[ADi]].Ip);
2014-06-16 14:50:35 +02:00
// request something special to get the vendor
ModbusReadRegisters(0x1000, 3); // Request B&R MAC address
2014-05-26 12:07:04 +02:00
}
/// <Step3>
void OnModbusReadRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap)
{
2014-06-16 14:50:35 +02:00
struct ModbusReqRead mbreq;
2014-05-26 12:07:04 +02:00
switch (error)
{
2014-06-16 09:23:21 +02:00
case Timeout:
return;
2014-05-26 12:07:04 +02:00
case Exception:
2014-06-16 14:50:35 +02:00
memcpy_n2h(mbreq, gQueueAck[mbap.TxID].Buffer);
2014-06-17 16:21:45 +02:00
if (mbreq.Address == 0x1000 && ex == IllegalDataAddress) // We requested Wago SerialCode and it didn't work --> Not Wago --> B&R. Not future proof
2014-06-16 14:50:35 +02:00
{
gIpsSorted[ips[ADi]].Vendor = Wago;
// request information
2014-07-10 09:56:55 +02:00
ADn = _DeviceGetInformation(Wago);
2014-06-16 14:50:35 +02:00
return;
}
2014-05-26 12:07:04 +02:00
writeLineEx(0, 3, "Error while analyzing %s! The device respond with exception code %d! Ignoring...", gIpsSorted[ips[ADi]].IP, ex);
break;
2014-06-16 14:50:35 +02:00
case FinalTimeout:
writeLineEx(0, 3, "Error while analyzing %s! The device did not respond! Ignoring...", gIpsSorted[ips[ADi]].IP);
break;
2014-07-11 13:32:02 +02:00
case NotSent:
writeLineEx(0, 3, "Error while analyzing %s! The device was not available! Ignoring...", gIpsSorted[ips[ADi]].IP);
break;
2014-05-21 13:37:57 +02:00
}
2014-06-16 09:23:21 +02:00
gQueueAck.Clear(); // Clear all queues
gQueuePending.Clear();
gQueueSent.Clear();
gIpsSorted.Remove(ips[ADi]); // Remove the IP
AnalyzeDevicesNext(); // And go to the next device
2014-05-21 13:37:57 +02:00
}
2014-05-26 12:07:04 +02:00
/// <Step3>
2014-05-27 13:29:24 +02:00
void OnModbusReadRegistersSuccess(struct ModbusResReceiveRegisters mbres, struct ModbusReqRead mbreq)
2014-05-26 12:07:04 +02:00
{
2014-06-16 14:50:35 +02:00
if (mbreq.Address == 0x1000) // We detected a B&R device
2014-05-26 12:07:04 +02:00
{
2014-06-16 14:50:35 +02:00
gIpsSorted[ips[ADi]].Vendor = BuR;
// request further information
2014-07-10 09:56:55 +02:00
ADn = _DeviceGetInformation(BuR);
2014-06-16 14:50:35 +02:00
return;
}
2014-07-10 09:56:55 +02:00
_DeviceParseRegister(gIpsSorted[ips[ADi]], mbreq.Address, mbres.Data, mbreq.Count);
2014-05-26 12:07:04 +02:00
2014-06-16 09:23:21 +02:00
if (--ADn == 0) // If we received all registers
2014-05-26 12:07:04 +02:00
AnalyzeDevicesNext();
}
// Step 4: Create the files with the queried data
/// <Step4>
void MakeFiles()
{
GenSysvars();
GenDbc();
stop();
}
2014-05-21 13:37:57 +02:00
// Generate the SysVars XML
2014-05-26 12:07:04 +02:00
/// <Step4>
2014-05-21 13:37:57 +02:00
void GenSysvars()
{
write("GenSysvars() -> %s", fnSysvar);
f.Open(fnSysvar, 0, 0); // rewrite file in ASCII
2014-06-12 17:28:05 +02:00
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");
2014-05-21 13:37:57 +02:00
for (long net : gIpNets)
{
2014-05-26 12:07:04 +02:00
byte nett;
nett = net;
2014-06-12 17:28:05 +02:00
PutString(" <namespace name=\"Ethernet");
PutString(nett);
PutString("\" comment=\"Subnet: 192.168.");
PutString(nett);
PutString(".\">\n");
2014-05-21 13:37:57 +02:00
for (long ipN : gIpsSorted)
{
if (((ipN >> 16) & 0xFF) != net)
continue;
2014-06-17 16:21:45 +02:00
DeviceInit(gIpsSorted[ipN].Vendor);
2014-05-21 13:37:57 +02:00
2014-06-12 17:28:05 +02:00
PutString(" <namespace name=\"Client_");
2014-07-11 13:32:02 +02:00
if (useThirdIpByteForNames)
{
PutString(gIpsSorted[ipN].IpNet);
PutString("_");
}
2014-06-12 17:28:05 +02:00
PutString(gIpsSorted[ipN].IpLsb);
PutString("\" comment=\"Server with ip address '");
PutString(gIpsSorted[ipN].Ip);
PutString("'\">\n");
2014-05-21 13:37:57 +02:00
2014-05-26 12:07:04 +02:00
// Namespace Config
2014-06-12 17:28:05 +02:00
PutString(" <namespace name=\"Config\" comment=\"Configuration section for this server\">\n");
2014-05-26 12:07:04 +02:00
// IP
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// Intveral
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
//Namespace Info
2014-06-12 17:28:05 +02:00
PutString(" <namespace name=\"Info\" comment=\"Some information about the device\">\n");
2014-05-26 13:58:28 +02:00
// Vendor
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// SerialCode
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// DeviceCode
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// Modules
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// InputRegisters
2014-06-12 17:28:05 +02:00
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);
2014-06-16 14:50:35 +02:00
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxRegisterCount);
2014-06-17 16:21:45 +02:00
PutString("\" maxValuePhys=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxRegisterCount);
2014-06-17 16:21:45 +02:00
PutString("\" />\n");
2014-05-26 12:07:04 +02:00
// InputBits
2014-06-12 17:28:05 +02:00
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);
2014-06-16 14:50:35 +02:00
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxBitCount);
2014-06-17 16:21:45 +02:00
PutString("\" maxValuePhys=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxBitCount);
2014-06-17 16:21:45 +02:00
PutString("\" />\n");
2014-05-26 12:07:04 +02:00
// OutputRegisters
2014-06-12 17:28:05 +02:00
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);
2014-06-16 14:50:35 +02:00
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxRegisterCount);
2014-06-17 16:21:45 +02:00
PutString("\" maxValuePhys=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxRegisterCount);
2014-06-17 16:21:45 +02:00
PutString("\" />\n");
2014-05-26 12:07:04 +02:00
// OutputBits
2014-06-12 17:28:05 +02:00
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);
2014-06-16 14:50:35 +02:00
PutString("\" minValue=\"0\" minValuePhys=\"0\" maxValue=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxBitCount);
2014-06-17 16:21:45 +02:00
PutString("\" maxValuePhys=\"");
2014-07-10 09:56:55 +02:00
PutString((word)thisDev.MaxBitCount);
2014-06-17 16:21:45 +02:00
PutString("\" />\n");
2014-06-12 17:28:05 +02:00
PutString(" </namespace>\n");
2014-05-26 12:07:04 +02:00
// Namespace Data
2014-06-12 17:28:05 +02:00
PutString(" <namespace name=\"Data\" comment=\"The actual process image\">\n");
2014-05-26 12:07:04 +02:00
// InputRegisters
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// InputBits
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// OutputRegisters
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
// OutputBits
2014-06-12 17:28:05 +02:00
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");
2014-05-26 12:07:04 +02:00
2014-06-12 17:28:05 +02:00
PutString(" </namespace>\n");
PutString(" </namespace>\n");
2014-05-21 13:37:57 +02:00
}
2014-06-12 17:28:05 +02:00
PutString(" </namespace>\n");
2014-05-21 13:37:57 +02:00
}
2014-06-12 17:28:05 +02:00
PutString(" </namespace>\n");
PutString("</systemvariables>\n");
2014-05-21 13:37:57 +02:00
f.Close();
}
// Generate the Database
2014-05-26 12:07:04 +02:00
/// <Step4>
2014-05-21 13:37:57 +02:00
void GenDbc()
{
write("GenDbc() -> %s", fnDbc);
f.Open(fnDbc, 0, 0); // rewrite file in ASCII
2014-06-12 17:28:05 +02:00
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_:");
2014-05-21 13:37:57 +02:00
for (long ipN : gIpsSorted)
{
2014-06-12 17:28:05 +02:00
PutString(" Client_");
2014-07-11 13:32:02 +02:00
if (useThirdIpByteForNames)
{
PutString(gIpsSorted[ipN].IpNet);
PutString("_");
}
2014-06-12 17:28:05 +02:00
PutString(gIpsSorted[ipN].IpLsb);
2014-05-21 13:37:57 +02:00
}
2014-06-12 17:28:05 +02:00
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");
2014-05-21 13:37:57 +02:00
f.Close();
}
2014-05-26 12:07:04 +02:00
2014-05-27 13:29:24 +02:00
2014-06-12 17:28:05 +02:00
// The stuff below is not needed
2014-05-27 13:29:24 +02:00
/// <zzzModbus>
void OnModbusClientPanics(enum FatalErrors reason)
{
writeLineEx(0, 4, "<%NODE_NAME%> FATAL! %d", reason);
2014-06-12 17:28:05 +02:00
/* switch(reason)
2014-05-27 13:29:24 +02:00
{
case ParsingBuffer:
case ModbusPackageWasSplit:
case DeviceCodeUnknown:
case VendorIdUnknown:
case ConnectionError:
break;
}
2014-06-12 17:28:05 +02:00
*/
2014-05-27 13:29:24 +02:00
}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteBitFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteRegisterFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteMasksFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusReadWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteBitsFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteRegistersFailed(enum ModbusRequestError error, enum ModbusException ex, struct ModbusApHeader mbap){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteBitSuccess(struct ModbusResConfirmSingle mbc){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteRegisterSuccess(struct ModbusResConfirmSingle mbc){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteBitsSuccess(struct ModbusResConfirmMultiple mbc){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteRegistersSuccess(struct ModbusResConfirmMultiple mbc){}
2014-05-26 13:58:28 +02:00
/// <zzzModbus>
2014-05-21 13:37:57 +02:00
void OnModbusWriteMasksSuccess(struct ModbusResConfirmMasks mbc){}